From ad19fbb39fe39a938209538291358d702e2666d7 Mon Sep 17 00:00:00 2001 From: bill tyler Date: Mon, 8 Feb 2016 18:01:48 +0000 Subject: [PATCH] additional experimental support for raspberry pi camera --- external_src/raspicam-0.1.3-1.zip | Bin 0 -> 608933 bytes external_src/raspicam-0.1.3.zip | Bin 0 -> 608933 bytes external_src/raspicam-0.1.3/CMakeLists.txt | 250 +++ external_src/raspicam-0.1.3/Changelog | 33 + external_src/raspicam-0.1.3/README | 207 +++ .../raspicam-0.1.3/build/CMakeCache.txt | 380 ++++ .../CMakeFiles/2.8.12.2/CMakeCCompiler.cmake | 56 + .../2.8.12.2/CMakeCXXCompiler.cmake | 57 + .../2.8.12.2/CMakeDetermineCompilerABI_C.bin | Bin 0 -> 8324 bytes .../CMakeDetermineCompilerABI_CXX.bin | Bin 0 -> 8353 bytes .../CMakeFiles/2.8.12.2/CMakeSystem.cmake | 15 + .../2.8.12.2/CompilerIdC/CMakeCCompilerId.c | 389 ++++ .../CMakeFiles/2.8.12.2/CompilerIdC/a.out | Bin 0 -> 8408 bytes .../CompilerIdCXX/CMakeCXXCompilerId.cpp | 377 ++++ .../CMakeFiles/2.8.12.2/CompilerIdCXX/a.out | Bin 0 -> 8433 bytes .../CMakeDirectoryInformation.cmake | 16 + .../build/CMakeFiles/CMakeOutput.log | 265 +++ .../build/CMakeFiles/CMakeRuleHashes.txt | 2 + .../build/CMakeFiles/Makefile.cmake | 87 + .../raspicam-0.1.3/build/CMakeFiles/Makefile2 | 345 ++++ .../build/CMakeFiles/TargetDirectories.txt | 7 + .../build/CMakeFiles/cmake.check_cache | 1 + .../build/CMakeFiles/progress.marks | 1 + .../CMakeFiles/uninstall.dir/DependInfo.cmake | 20 + .../build/CMakeFiles/uninstall.dir/build.make | 66 + .../uninstall.dir/cmake_clean.cmake | 8 + .../CMakeFiles/uninstall.dir/progress.make | 1 + .../raspicam-0.1.3/build/Findraspicam.cmake | 34 + external_src/raspicam-0.1.3/build/Makefile | 265 +++ .../raspicam-0.1.3/build/cmake_install.cmake | 59 + .../build/cmake_uninstall.cmake | 28 + .../raspicam-0.1.3/build/raspicamConfig.cmake | 34 + .../CMakeDirectoryInformation.cmake | 16 + .../build/src/CMakeFiles/progress.marks | 1 + .../CMakeFiles/raspicam.dir/DependInfo.cmake | 38 + .../src/CMakeFiles/raspicam.dir/build.make | 214 +++ .../CMakeFiles/raspicam.dir/cmake_clean.cmake | 16 + .../src/CMakeFiles/raspicam.dir/depend.make | 2 + .../src/CMakeFiles/raspicam.dir/flags.make | 8 + .../src/CMakeFiles/raspicam.dir/link.txt | 1 + .../src/CMakeFiles/raspicam.dir/progress.make | 6 + .../raspicam_cv.dir/DependInfo.cmake | 28 + .../src/CMakeFiles/raspicam_cv.dir/build.make | 158 ++ .../raspicam_cv.dir/cmake_clean.cmake | 11 + .../CMakeFiles/raspicam_cv.dir/depend.make | 2 + .../src/CMakeFiles/raspicam_cv.dir/flags.make | 8 + .../src/CMakeFiles/raspicam_cv.dir/link.txt | 1 + .../CMakeFiles/raspicam_cv.dir/progress.make | 3 + .../raspicam-0.1.3/build/src/Makefile | 386 ++++ .../build/src/cmake_install.cmake | 95 + .../CMakeDirectoryInformation.cmake | 16 + .../build/utils/CMakeFiles/progress.marks | 1 + .../DependInfo.cmake | 28 + .../raspicam_cv_still_test.dir/build.make | 124 ++ .../cmake_clean.cmake | 10 + .../raspicam_cv_still_test.dir/depend.make | 2 + .../raspicam_cv_still_test.dir/flags.make | 8 + .../raspicam_cv_still_test.dir/link.txt | 1 + .../raspicam_cv_still_test.dir/progress.make | 2 + .../raspicam_cv_test.dir/DependInfo.cmake | 28 + .../raspicam_cv_test.dir/build.make | 124 ++ .../raspicam_cv_test.dir/cmake_clean.cmake | 10 + .../raspicam_cv_test.dir/depend.make | 2 + .../raspicam_cv_test.dir/flags.make | 8 + .../CMakeFiles/raspicam_cv_test.dir/link.txt | 1 + .../raspicam_cv_test.dir/progress.make | 2 + .../raspicam_still_test.dir/DependInfo.cmake | 27 + .../raspicam_still_test.dir/build.make | 106 ++ .../raspicam_still_test.dir/cmake_clean.cmake | 10 + .../raspicam_still_test.dir/depend.make | 2 + .../raspicam_still_test.dir/flags.make | 8 + .../raspicam_still_test.dir/link.txt | 1 + .../raspicam_still_test.dir/progress.make | 2 + .../raspicam_test.dir/DependInfo.cmake | 27 + .../CMakeFiles/raspicam_test.dir/build.make | 106 ++ .../raspicam_test.dir/cmake_clean.cmake | 10 + .../CMakeFiles/raspicam_test.dir/depend.make | 2 + .../CMakeFiles/raspicam_test.dir/flags.make | 8 + .../CMakeFiles/raspicam_test.dir/link.txt | 1 + .../raspicam_test.dir/progress.make | 2 + .../raspicam-0.1.3/build/utils/Makefile | 335 ++++ .../build/utils/cmake_install.cmake | 106 ++ .../raspicam-0.1.3/cmake_uninstall.cmake.in | 28 + external_src/raspicam-0.1.3/config.cmake.in | 34 + .../dependencies/mmal/CMakeLists.txt | 46 + .../dependencies/mmal/client/CMakeLists.txt | 1 + .../mmal/client/brcmjpeg/CMakeLists.txt | 6 + .../mmal/client/brcmjpeg/brcmjpeg.c | 914 ++++++++++ .../mmal/client/brcmjpeg/brcmjpeg.h | 152 ++ .../mmal/client/brcmjpeg/brcmjpeg_test.c | 236 +++ .../mmal/components/CMakeLists.txt | 34 + .../mmal/components/aaf_audio_render.cpp | 504 ++++++ .../dependencies/mmal/components/aggregator.c | 188 ++ .../mmal/components/android_media_codec.cpp | 861 +++++++++ .../mmal/components/artificial_camera.c | 287 +++ .../mmal/components/avcodec_audio_decoder.c | 607 +++++++ .../mmal/components/avcodec_video_decoder.c | 586 ++++++ .../dependencies/mmal/components/clock.c | 900 ++++++++++ .../mmal/components/container_reader.c | 1000 +++++++++++ .../dependencies/mmal/components/copy.c | 327 ++++ .../dependencies/mmal/components/null_sink.c | 125 ++ .../mmal/components/passthrough.c | 284 +++ .../dependencies/mmal/components/scheduler.c | 485 +++++ .../mmal/components/sdl_audio_render.c | 278 +++ .../mmal/components/sdl_video_render.c | 394 ++++ .../dependencies/mmal/components/spdif.c | 496 ++++++ .../dependencies/mmal/components/splitter.c | 345 ++++ .../dependencies/mmal/core/CMakeLists.txt | 24 + .../dependencies/mmal/core/mmal_buffer.c | 188 ++ .../mmal/core/mmal_buffer_private.h | 86 + .../dependencies/mmal/core/mmal_clock.c | 892 ++++++++++ .../mmal/core/mmal_clock_private.h | 204 +++ .../dependencies/mmal/core/mmal_component.c | 780 ++++++++ .../mmal/core/mmal_component_private.h | 169 ++ .../mmal/core/mmal_core_private.h | 40 + .../dependencies/mmal/core/mmal_events.c | 138 ++ .../mmal/core/mmal_events_private.h | 67 + .../dependencies/mmal/core/mmal_format.c | 183 ++ .../dependencies/mmal/core/mmal_logging.c | 43 + .../dependencies/mmal/core/mmal_pool.c | 303 ++++ .../dependencies/mmal/core/mmal_port.c | 1508 ++++++++++++++++ .../dependencies/mmal/core/mmal_port_clock.c | 803 +++++++++ .../mmal/core/mmal_port_private.h | 213 +++ .../dependencies/mmal/core/mmal_queue.c | 166 ++ .../raspicam-0.1.3/dependencies/mmal/mmal.h | 390 ++++ .../dependencies/mmal/mmal_buffer.h | 250 +++ .../dependencies/mmal/mmal_clock.h | 202 +++ .../dependencies/mmal/mmal_common.h | 83 + .../dependencies/mmal/mmal_component.h | 148 ++ .../dependencies/mmal/mmal_encodings.h | 208 +++ .../dependencies/mmal/mmal_events.h | 109 ++ .../dependencies/mmal/mmal_format.h | 223 +++ .../dependencies/mmal/mmal_logging.h | 71 + .../dependencies/mmal/mmal_metadata.h | 84 + .../dependencies/mmal/mmal_parameters.h | 194 ++ .../dependencies/mmal/mmal_parameters_audio.h | 66 + .../mmal/mmal_parameters_camera.h | 755 ++++++++ .../dependencies/mmal/mmal_parameters_clock.h | 88 + .../mmal/mmal_parameters_common.h | 191 ++ .../dependencies/mmal/mmal_parameters_video.h | 486 +++++ .../dependencies/mmal/mmal_pool.h | 167 ++ .../dependencies/mmal/mmal_port.h | 286 +++ .../dependencies/mmal/mmal_queue.h | 116 ++ .../dependencies/mmal/mmal_types.h | 100 ++ .../mmal/openmaxil/CMakeLists.txt | 20 + .../dependencies/mmal/openmaxil/mmalomx.h | 130 ++ .../mmal/openmaxil/mmalomx_buffer.c | 235 +++ .../mmal/openmaxil/mmalomx_buffer.h | 39 + .../mmal/openmaxil/mmalomx_commands.c | 462 +++++ .../mmal/openmaxil/mmalomx_commands.h | 85 + .../mmal/openmaxil/mmalomx_core.c | 1577 +++++++++++++++++ .../mmal/openmaxil/mmalomx_logging.c | 176 ++ .../mmal/openmaxil/mmalomx_logging.h | 46 + .../mmal/openmaxil/mmalomx_marks.c | 101 ++ .../mmal/openmaxil/mmalomx_marks.h | 36 + .../mmal/openmaxil/mmalomx_parameters.c | 578 ++++++ .../mmal/openmaxil/mmalomx_parameters.h | 37 + .../mmal/openmaxil/mmalomx_registry.c | 159 ++ .../mmal/openmaxil/mmalomx_registry.h | 41 + .../mmal/openmaxil/mmalomx_roles.c | 210 +++ .../mmal/openmaxil/mmalomx_roles.h | 61 + .../mmal/openmaxil/mmalomx_util_params.c | 193 ++ .../mmal/openmaxil/mmalomx_util_params.h | 114 ++ .../openmaxil/mmalomx_util_params_audio.c | 34 + .../openmaxil/mmalomx_util_params_camera.c | 556 ++++++ .../openmaxil/mmalomx_util_params_common.h | 133 ++ .../mmal/openmaxil/mmalomx_util_params_misc.c | 157 ++ .../openmaxil/mmalomx_util_params_video.c | 277 +++ .../dependencies/mmal/test/CMakeLists.txt | 26 + .../mmal/test/examples/example_basic_1.c | 238 +++ .../mmal/test/examples/example_basic_2.c | 304 ++++ .../mmal/test/examples/example_connections.c | 192 ++ .../mmal/test/examples/example_graph.c | 95 + .../dependencies/mmal/util/CMakeLists.txt | 28 + .../mmal/util/mmal_component_wrapper.c | 368 ++++ .../mmal/util/mmal_component_wrapper.h | 157 ++ .../dependencies/mmal/util/mmal_connection.c | 513 ++++++ .../dependencies/mmal/util/mmal_connection.h | 230 +++ .../mmal/util/mmal_default_components.h | 90 + .../dependencies/mmal/util/mmal_graph.c | 1479 ++++++++++++++++ .../dependencies/mmal/util/mmal_graph.h | 243 +++ .../dependencies/mmal/util/mmal_il.c | 915 ++++++++++ .../dependencies/mmal/util/mmal_il.h | 212 +++ .../dependencies/mmal/util/mmal_list.c | 221 +++ .../dependencies/mmal/util/mmal_list.h | 127 ++ .../mmal/util/mmal_param_convert.c | 177 ++ .../mmal/util/mmal_param_convert.h | 92 + .../dependencies/mmal/util/mmal_util.c | 355 ++++ .../dependencies/mmal/util/mmal_util.h | 173 ++ .../dependencies/mmal/util/mmal_util_params.c | 223 +++ .../dependencies/mmal/util/mmal_util_params.h | 210 +++ .../mmal/util/mmal_util_rational.c | 158 ++ .../mmal/util/mmal_util_rational.h | 127 ++ .../dependencies/mmal/vc/CMakeLists.txt | 29 + .../dependencies/mmal/vc/mmal_vc_api.c | 1481 ++++++++++++++++ .../dependencies/mmal/vc/mmal_vc_api.h | 219 +++ .../dependencies/mmal/vc/mmal_vc_api_drm.c | 77 + .../dependencies/mmal/vc/mmal_vc_api_drm.h | 55 + .../dependencies/mmal/vc/mmal_vc_client.c | 822 +++++++++ .../mmal/vc/mmal_vc_client_priv.h | 80 + .../dependencies/mmal/vc/mmal_vc_dbglog.h | 160 ++ .../dependencies/mmal/vc/mmal_vc_diag.c | 843 +++++++++ .../dependencies/mmal/vc/mmal_vc_msgnames.c | 77 + .../dependencies/mmal/vc/mmal_vc_msgnames.h | 37 + .../dependencies/mmal/vc/mmal_vc_msgs.h | 525 ++++++ .../mmal/vc/mmal_vc_opaque_alloc.c | 87 + .../mmal/vc/mmal_vc_opaque_alloc.h | 73 + .../dependencies/mmal/vc/mmal_vc_shm.c | 235 +++ .../dependencies/mmal/vc/mmal_vc_shm.h | 62 + .../dependencies/vcos/CMakeLists.txt | 68 + .../dependencies/vcos/generic/CMakeLists.txt | 21 + .../dependencies/vcos/generic/vcos_abort.c | 85 + .../dependencies/vcos/generic/vcos_cmd.c | 722 ++++++++ .../dependencies/vcos/generic/vcos_common.h | 96 + .../vcos/generic/vcos_deprecated.h | 36 + .../vcos/generic/vcos_generic_blockpool.c | 568 ++++++ .../vcos/generic/vcos_generic_blockpool.h | 294 +++ .../vcos/generic/vcos_generic_event_flags.c | 320 ++++ .../vcos/generic/vcos_generic_event_flags.h | 127 ++ .../vcos/generic/vcos_generic_named_sem.c | 268 +++ .../vcos/generic/vcos_generic_named_sem.h | 101 ++ .../generic/vcos_generic_quickslow_mutex.h | 95 + .../vcos/generic/vcos_generic_reentrant_mtx.c | 76 + .../vcos/generic/vcos_generic_reentrant_mtx.h | 95 + .../vcos/generic/vcos_generic_safe_string.c | 130 ++ .../vcos/generic/vcos_generic_tls.h | 164 ++ .../dependencies/vcos/generic/vcos_init.c | 84 + .../generic/vcos_joinable_thread_from_plain.h | 229 +++ .../vcos/generic/vcos_latch_from_sem.h | 68 + .../dependencies/vcos/generic/vcos_logcat.c | 587 ++++++ .../vcos/generic/vcos_mem_from_malloc.c | 98 + .../vcos/generic/vcos_mem_from_malloc.h | 74 + .../dependencies/vcos/generic/vcos_msgqueue.c | 389 ++++ .../vcos/generic/vcos_mutexes_are_reentrant.h | 88 + .../vcos/generic/vcos_thread_reaper.h | 55 + .../dependencies/vcos/glibc/vcos_backtrace.c | 56 + .../dependencies/vcos/pthreads/CMakeLists.txt | 46 + .../dependencies/vcos/pthreads/vcos_dlfcn.c | 71 + .../vcos/pthreads/vcos_futex_mutex.h | 102 ++ .../vcos/pthreads/vcos_platform.h | 746 ++++++++ .../vcos/pthreads/vcos_platform_types.h | 71 + .../vcos/pthreads/vcos_pthreads.c | 902 ++++++++++ .../dependencies/vcos/user_nodefs.h | 47 + .../raspicam-0.1.3/dependencies/vcos/vcos.h | 221 +++ .../dependencies/vcos/vcos_assert.h | 324 ++++ .../dependencies/vcos/vcos_atomic_flags.h | 92 + .../dependencies/vcos/vcos_attr.h | 153 ++ .../dependencies/vcos/vcos_blockpool.h | 171 ++ .../dependencies/vcos/vcos_build_info.h | 32 + .../dependencies/vcos/vcos_cfg.h | 126 ++ .../dependencies/vcos/vcos_cmd.h | 119 ++ .../dependencies/vcos/vcos_ctype.h | 49 + .../dependencies/vcos/vcos_dlfcn.h | 86 + .../dependencies/vcos/vcos_event.h | 117 ++ .../dependencies/vcos/vcos_event_flags.h | 118 ++ .../dependencies/vcos/vcos_init.h | 110 ++ .../dependencies/vcos/vcos_inttypes.h | 49 + .../dependencies/vcos/vcos_isr.h | 90 + .../dependencies/vcos/vcos_legacy_isr.h | 102 ++ .../dependencies/vcos/vcos_logging.h | 315 ++++ .../dependencies/vcos/vcos_logging_control.h | 28 + .../dependencies/vcos/vcos_lowlevel_thread.h | 129 ++ .../dependencies/vcos/vcos_mem.h | 101 ++ .../dependencies/vcos/vcos_mempool.h | 109 ++ .../dependencies/vcos/vcos_msgqueue.h | 280 +++ .../dependencies/vcos/vcos_mutex.h | 112 ++ .../dependencies/vcos/vcos_named_semaphore.h | 113 ++ .../dependencies/vcos/vcos_once.h | 62 + .../dependencies/vcos/vcos_queue.h | 105 ++ .../dependencies/vcos/vcos_quickslow_mutex.h | 101 ++ .../dependencies/vcos/vcos_reentrant_mutex.h | 86 + .../dependencies/vcos/vcos_semaphore.h | 158 ++ .../dependencies/vcos/vcos_stdbool.h | 47 + .../dependencies/vcos/vcos_stdint.h | 107 ++ .../dependencies/vcos/vcos_string.h | 129 ++ .../dependencies/vcos/vcos_thread.h | 282 +++ .../dependencies/vcos/vcos_thread_attr.h | 96 + .../dependencies/vcos/vcos_timer.h | 117 ++ .../dependencies/vcos/vcos_tls.h | 84 + .../dependencies/vcos/vcos_types.h | 283 +++ .../raspicam-0.1.3/src/CMakeLists.txt | 53 + .../raspicam-0.1.3/src/private/exceptions.h | 114 ++ .../src/private/fake_mmal_dependencies.cpp | 395 +++++ .../src/private/private_impl.cpp | 812 +++++++++ .../raspicam-0.1.3/src/private/private_impl.h | 280 +++ .../src/private/private_types.h | 116 ++ .../src/private/threadcondition.cpp | 72 + .../src/private/threadcondition.h | 74 + .../src/private_still/private_still_impl.cpp | 850 +++++++++ .../src/private_still/private_still_impl.h | 173 ++ external_src/raspicam-0.1.3/src/raspicam.cpp | 166 ++ external_src/raspicam-0.1.3/src/raspicam.h | 178 ++ .../raspicam-0.1.3/src/raspicam_cv.cpp | 214 +++ external_src/raspicam-0.1.3/src/raspicam_cv.h | 115 ++ .../raspicam-0.1.3/src/raspicam_still.cpp | 167 ++ .../raspicam-0.1.3/src/raspicam_still.h | 111 ++ .../raspicam-0.1.3/src/raspicam_still_cv.cpp | 185 ++ .../raspicam-0.1.3/src/raspicam_still_cv.h | 118 ++ .../raspicam-0.1.3/src/raspicamtypes.h | 132 ++ external_src/raspicam-0.1.3/src/scaler.h | 47 + .../raspicam-0.1.3/utils/CMakeLists.txt | 18 + .../utils/raspicam_cv_still_test.cpp | 82 + .../raspicam-0.1.3/utils/raspicam_cv_test.cpp | 148 ++ .../utils/raspicam_still_test.cpp | 87 + .../raspicam-0.1.3/utils/raspicam_test.cpp | 234 +++ 305 files changed, 58254 insertions(+) create mode 100644 external_src/raspicam-0.1.3-1.zip create mode 100644 external_src/raspicam-0.1.3.zip create mode 100644 external_src/raspicam-0.1.3/CMakeLists.txt create mode 100644 external_src/raspicam-0.1.3/Changelog create mode 100644 external_src/raspicam-0.1.3/README create mode 100644 external_src/raspicam-0.1.3/build/CMakeCache.txt create mode 100644 external_src/raspicam-0.1.3/build/CMakeFiles/2.8.12.2/CMakeCCompiler.cmake create mode 100644 external_src/raspicam-0.1.3/build/CMakeFiles/2.8.12.2/CMakeCXXCompiler.cmake create mode 100755 external_src/raspicam-0.1.3/build/CMakeFiles/2.8.12.2/CMakeDetermineCompilerABI_C.bin create mode 100755 external_src/raspicam-0.1.3/build/CMakeFiles/2.8.12.2/CMakeDetermineCompilerABI_CXX.bin create mode 100644 external_src/raspicam-0.1.3/build/CMakeFiles/2.8.12.2/CMakeSystem.cmake create mode 100644 external_src/raspicam-0.1.3/build/CMakeFiles/2.8.12.2/CompilerIdC/CMakeCCompilerId.c create mode 100755 external_src/raspicam-0.1.3/build/CMakeFiles/2.8.12.2/CompilerIdC/a.out create mode 100644 external_src/raspicam-0.1.3/build/CMakeFiles/2.8.12.2/CompilerIdCXX/CMakeCXXCompilerId.cpp create mode 100755 external_src/raspicam-0.1.3/build/CMakeFiles/2.8.12.2/CompilerIdCXX/a.out create mode 100644 external_src/raspicam-0.1.3/build/CMakeFiles/CMakeDirectoryInformation.cmake create mode 100644 external_src/raspicam-0.1.3/build/CMakeFiles/CMakeOutput.log create mode 100644 external_src/raspicam-0.1.3/build/CMakeFiles/CMakeRuleHashes.txt create mode 100644 external_src/raspicam-0.1.3/build/CMakeFiles/Makefile.cmake create mode 100644 external_src/raspicam-0.1.3/build/CMakeFiles/Makefile2 create mode 100644 external_src/raspicam-0.1.3/build/CMakeFiles/TargetDirectories.txt create mode 100644 external_src/raspicam-0.1.3/build/CMakeFiles/cmake.check_cache create mode 100644 external_src/raspicam-0.1.3/build/CMakeFiles/progress.marks create mode 100644 external_src/raspicam-0.1.3/build/CMakeFiles/uninstall.dir/DependInfo.cmake create mode 100644 external_src/raspicam-0.1.3/build/CMakeFiles/uninstall.dir/build.make create mode 100644 external_src/raspicam-0.1.3/build/CMakeFiles/uninstall.dir/cmake_clean.cmake create mode 100644 external_src/raspicam-0.1.3/build/CMakeFiles/uninstall.dir/progress.make create mode 100644 external_src/raspicam-0.1.3/build/Findraspicam.cmake create mode 100644 external_src/raspicam-0.1.3/build/Makefile create mode 100644 external_src/raspicam-0.1.3/build/cmake_install.cmake create mode 100644 external_src/raspicam-0.1.3/build/cmake_uninstall.cmake create mode 100644 external_src/raspicam-0.1.3/build/raspicamConfig.cmake create mode 100644 external_src/raspicam-0.1.3/build/src/CMakeFiles/CMakeDirectoryInformation.cmake create mode 100644 external_src/raspicam-0.1.3/build/src/CMakeFiles/progress.marks create mode 100644 external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/DependInfo.cmake create mode 100644 external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/build.make create mode 100644 external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/cmake_clean.cmake create mode 100644 external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/depend.make create mode 100644 external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/flags.make create mode 100644 external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/link.txt create mode 100644 external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/progress.make create mode 100644 external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/DependInfo.cmake create mode 100644 external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/build.make create mode 100644 external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/cmake_clean.cmake create mode 100644 external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/depend.make create mode 100644 external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/flags.make create mode 100644 external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/link.txt create mode 100644 external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/progress.make create mode 100644 external_src/raspicam-0.1.3/build/src/Makefile create mode 100644 external_src/raspicam-0.1.3/build/src/cmake_install.cmake create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/CMakeDirectoryInformation.cmake create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/progress.marks create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/DependInfo.cmake create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/build.make create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/cmake_clean.cmake create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/depend.make create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/flags.make create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/link.txt create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/progress.make create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/DependInfo.cmake create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/build.make create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/cmake_clean.cmake create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/depend.make create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/flags.make create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/link.txt create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/progress.make create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/DependInfo.cmake create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/build.make create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/cmake_clean.cmake create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/depend.make create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/flags.make create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/link.txt create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/progress.make create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/DependInfo.cmake create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/build.make create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/cmake_clean.cmake create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/depend.make create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/flags.make create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/link.txt create mode 100644 external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/progress.make create mode 100644 external_src/raspicam-0.1.3/build/utils/Makefile create mode 100644 external_src/raspicam-0.1.3/build/utils/cmake_install.cmake create mode 100644 external_src/raspicam-0.1.3/cmake_uninstall.cmake.in create mode 100644 external_src/raspicam-0.1.3/config.cmake.in create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/CMakeLists.txt create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/client/CMakeLists.txt create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/client/brcmjpeg/CMakeLists.txt create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/client/brcmjpeg/brcmjpeg.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/client/brcmjpeg/brcmjpeg.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/client/brcmjpeg/brcmjpeg_test.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/components/CMakeLists.txt create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/components/aaf_audio_render.cpp create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/components/aggregator.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/components/android_media_codec.cpp create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/components/artificial_camera.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/components/avcodec_audio_decoder.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/components/avcodec_video_decoder.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/components/clock.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/components/container_reader.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/components/copy.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/components/null_sink.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/components/passthrough.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/components/scheduler.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/components/sdl_audio_render.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/components/sdl_video_render.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/components/spdif.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/components/splitter.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/core/CMakeLists.txt create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_buffer.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_buffer_private.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_clock.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_clock_private.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_component.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_component_private.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_core_private.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_events.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_events_private.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_format.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_logging.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_pool.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_port.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_port_clock.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_port_private.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_queue.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal_buffer.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal_clock.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal_common.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal_component.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal_encodings.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal_events.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal_format.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal_logging.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal_metadata.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_audio.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_camera.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_clock.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_common.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_video.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal_pool.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal_port.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal_queue.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/mmal_types.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/CMakeLists.txt create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_buffer.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_buffer.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_commands.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_commands.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_core.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_logging.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_logging.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_marks.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_marks.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_parameters.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_parameters.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_registry.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_registry.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_roles.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_roles.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_audio.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_camera.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_common.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_misc.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_video.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/test/CMakeLists.txt create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/test/examples/example_basic_1.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/test/examples/example_basic_2.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/test/examples/example_connections.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/test/examples/example_graph.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/CMakeLists.txt create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_component_wrapper.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_component_wrapper.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_connection.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_connection.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_default_components.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_graph.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_graph.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_il.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_il.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_list.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_list.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_param_convert.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_param_convert.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util_params.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util_params.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util_rational.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util_rational.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/vc/CMakeLists.txt create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_api.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_api.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_api_drm.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_api_drm.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_client.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_client_priv.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_dbglog.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_diag.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_msgnames.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_msgnames.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_msgs.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_opaque_alloc.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_opaque_alloc.h create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_shm.c create mode 100644 external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_shm.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/CMakeLists.txt create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/CMakeLists.txt create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_abort.c create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_cmd.c create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_common.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_deprecated.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_blockpool.c create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_blockpool.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_event_flags.c create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_event_flags.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_named_sem.c create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_named_sem.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_quickslow_mutex.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_reentrant_mtx.c create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_reentrant_mtx.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_safe_string.c create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_tls.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_init.c create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_joinable_thread_from_plain.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_latch_from_sem.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_logcat.c create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_mem_from_malloc.c create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_mem_from_malloc.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_msgqueue.c create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_mutexes_are_reentrant.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_thread_reaper.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/glibc/vcos_backtrace.c create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/pthreads/CMakeLists.txt create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/pthreads/vcos_dlfcn.c create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/pthreads/vcos_futex_mutex.h create mode 100755 external_src/raspicam-0.1.3/dependencies/vcos/pthreads/vcos_platform.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/pthreads/vcos_platform_types.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/pthreads/vcos_pthreads.c create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/user_nodefs.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_assert.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_atomic_flags.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_attr.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_blockpool.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_build_info.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_cfg.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_cmd.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_ctype.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_dlfcn.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_event.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_event_flags.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_init.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_inttypes.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_isr.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_legacy_isr.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_logging.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_logging_control.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_lowlevel_thread.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_mem.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_mempool.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_msgqueue.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_mutex.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_named_semaphore.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_once.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_queue.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_quickslow_mutex.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_reentrant_mutex.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_semaphore.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_stdbool.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_stdint.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_string.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_thread.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_thread_attr.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_timer.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_tls.h create mode 100644 external_src/raspicam-0.1.3/dependencies/vcos/vcos_types.h create mode 100644 external_src/raspicam-0.1.3/src/CMakeLists.txt create mode 100644 external_src/raspicam-0.1.3/src/private/exceptions.h create mode 100644 external_src/raspicam-0.1.3/src/private/fake_mmal_dependencies.cpp create mode 100644 external_src/raspicam-0.1.3/src/private/private_impl.cpp create mode 100644 external_src/raspicam-0.1.3/src/private/private_impl.h create mode 100644 external_src/raspicam-0.1.3/src/private/private_types.h create mode 100644 external_src/raspicam-0.1.3/src/private/threadcondition.cpp create mode 100644 external_src/raspicam-0.1.3/src/private/threadcondition.h create mode 100644 external_src/raspicam-0.1.3/src/private_still/private_still_impl.cpp create mode 100644 external_src/raspicam-0.1.3/src/private_still/private_still_impl.h create mode 100644 external_src/raspicam-0.1.3/src/raspicam.cpp create mode 100644 external_src/raspicam-0.1.3/src/raspicam.h create mode 100644 external_src/raspicam-0.1.3/src/raspicam_cv.cpp create mode 100644 external_src/raspicam-0.1.3/src/raspicam_cv.h create mode 100644 external_src/raspicam-0.1.3/src/raspicam_still.cpp create mode 100644 external_src/raspicam-0.1.3/src/raspicam_still.h create mode 100644 external_src/raspicam-0.1.3/src/raspicam_still_cv.cpp create mode 100644 external_src/raspicam-0.1.3/src/raspicam_still_cv.h create mode 100644 external_src/raspicam-0.1.3/src/raspicamtypes.h create mode 100644 external_src/raspicam-0.1.3/src/scaler.h create mode 100644 external_src/raspicam-0.1.3/utils/CMakeLists.txt create mode 100644 external_src/raspicam-0.1.3/utils/raspicam_cv_still_test.cpp create mode 100644 external_src/raspicam-0.1.3/utils/raspicam_cv_test.cpp create mode 100644 external_src/raspicam-0.1.3/utils/raspicam_still_test.cpp create mode 100644 external_src/raspicam-0.1.3/utils/raspicam_test.cpp diff --git a/external_src/raspicam-0.1.3-1.zip b/external_src/raspicam-0.1.3-1.zip new file mode 100644 index 0000000000000000000000000000000000000000..a8e6f206debe8c83f35a38dd4a6b7e7451049eb2 GIT binary patch literal 608933 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

RTLpiFj}bB@)D_O={P$# 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

R=EeJ*U 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

P38z zbnG*$GI#AMmE*Q!j8$*8NT^;2bC8Y>d&&+Z z805mZ*ueziFnct5XFBRiv7-~*RIAv;4hJhOv?XY9CeI0#$VX+$jXLQNsS11fm;?#j zMm-L;cdgV1`j8fbY6eg3bD?FXcAxx;lZR6zW&xbbU7&CD;~IST^25x?<{e+|QQGYv z)R@SmtVYY_dYXzES9_8eVuTnieaDkLwDzPZUc!Q;A2W}<5jE5l2T$=jMQza8axrASk@fCMPC z*1qoS*6#4{uT~xh24=CyrDndqPVTY|cAkb5X?X{nY|bvuvc1psbr*Ydo`q+4dVlcv z(nAPI#L0#UK<+FJ3}%l|gS f`%%T#4d#8}g?QW>~2_!35@?0KN(#fIs%N-18gk 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�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≧xxu7Rv2MpAw?QVe7`K z5~XU(fZd==VaPcgdmjF%K8d=o6|6R5P?W!6n-wx^5qMWw0=7GN^PPiDt?C~WQ~j4% zVhL6l2)mSB0bTx+$Z?R)l1HA(r2bCHa|fm;o4oJDe%>o*GhB7qyx$>Icj{4teBFF+ zYh?loPT#U09W`!`H5WR}TH!nZJ^kq#`urn0k zLA+0Fm}kpKs$=MGvQF^Jv>?7)sJCknULdY}x)ATF4BD42tP{!$y??rYOWHwy+Rt&V z5aj^)9Dej|1kokK9ihN%9&hU3A;iqTr2aQ`_i-OuDBekGsbuV>U)-i{@ggsN$sSbW zoA1KDf;SbfdagR~F^#f)>d&?cAEv6y(2D=VI85`>Uz^cAvO3V}i^Njt6XXGax;OW# z(cSAPPYinZUY++~X^xxN*k^eY{_8UrAtIv1}47GLHjoMB>(+WOfYIuM$K|XN}=Ji`- zoN1~_KAsX;C?59gLW_+z8n%qIL3Q73G4Nr}Q3;tJ?ENjQ@W>4@mW zZIgIt@C+y;t8oT|m1+b~9_q@eiIE)|WeVd_q6ug?syz}&RY#08&=2_{?hCX+P``&1 zB{L(#Ncw^#jva)eq&g^$R=9!h%pkV%r4XjTWJwH@tEZrB%7sKEsfM&2qC(DOC^@$f)2VD=Mv{1-mgq>xV5yWGPcufJKAg=qT2B z3eN^hAV+ir9a5?wsHH7p5M^lbyFt;8f z{^}Ui&H&qQ16W^fLMhPLi#sa!Os~@bzarIUu;(6Dc^GV{*%JroXaxv+=^mPrP0P^N zk2-BV{b74Gt(^myVIoWAZcX_h;rn-r6Jn1YAk)G<~I z$^5WCNB`LmbpjYfy_O?U=yT%JJUY$KZoQUfJ>$bRhzq1_8%-5Y^^=`Tf6_}T*_7?? zvFnYdQOhha#ZO2ZzA#*Zd@j32s2oAK)AQ*a&PsD6f&)#l6+|?+!pB=^5bLlvjH%+coHBY`_8hJ~d4P((wusX}vd!qvWl= zhn+o~TVSP}V)!9WF3gcJM=;|m`FBa7BdmL%K)YVqM>$Y&yz9VbU<+bZA`IY*c0I&C zHEMaB(VG6-)n>M=Zrp+SM3a3F5-5L}MTqoZ8E1qWv%^6r8=O;sk$j^JQM3~*mCVu> z!-w!nj{>SuTFI(EF-*;vB7f!o84BQb+2js}1Pf`0z8WNkwo&e#I@9(Yxj82VwcuP9 zI2%yEkau@$R(toXbNn+y3Vx?edp#$lxhX^xsjBxsK+wNw!QGqfYw+TA!i9ovE{cy8 z!aqoVN%xYZh4Rv?&?W;1#y=~qgp$A_1iAQP*uRhsCUfPIX2b~iqXCi>y2>t-^ zLBXL|N44n470l(4-k?>^!w$qO3kG8fl#45?NszlqR?lbr?A$a7mt1DOgtHBph>hWX z{{=0#T9DYiD7)xt-HYrgH65t3L}gNtcA>Qjod%*3!Zs3Vq9Y%Qw`F=Oo|Axwky>c`{ltYBO80j-SHHHTetw;e<6A=V30w8a-`7SGPQ~ zEG|YX*OtXTtZfD7B)6pvtnws1oYJGEJnGnkx8UgVwP}uiC_)RMVr+YS%bBWoLkihTBht&;8S~{ zop@~+GxFLZ>Lql(&7I>CYlqMf`J6vKq7zR3#DyKxP+&tXyae2g#x++MIj`HKO#(}zlVhef^*t_kKimhZt zZN;@ggUyKkB<@CoE7qpUeo2*ZsP%zyQMnfH)%v&VX7}gA6dLhfr!DL1ZL=A?fzq|b zEQ^{hpj!3~Ot{#t6SlsK?mX4H^DuZusuaN}RnQ6B=M&s@xVq8@lC}YbSyoJipUulK zwYn4NP@Xo*XHk_^WSf?AnPEY)6#SSzJ4nJY$c8UkMCKFREw+G7zkwXh(p_yZ`&{Nf z>8)-p5GU_8o2ibAKk6Q;q#iSKke$Sps0k#u1sE9(@p~p#+hnp9L`C#VPpYN5@&}UH z_tv_+tzt)7k*un!$Cz#JH=C=Wseqpz8U}0v`ug%&IRAbpRK4v-E439?f@K}qcra)G zBADB*V-57%thb#i)510P;@w<`&k&o}j%#yo^Gu%hARJBVx}GfH^$oruko=ko4`|Bh zIj;d<_u`+N&Lki3XXQ@q%1#V44_~|8RR}%m&s_L0Ti8d^N>zr2Yz5^40-UhN89{$){q;>sQ5d@|e_fBvUE;{S0KgwKFWE5QN) z_>=wr;3{DJ?V$u_*NsPC&e4z?(&V?P2iwNo#8DLM8b5VNP z));9L4tb1}`}Q@D$KItb2UUXGsY20g`-vUmW|93SBgj4JGR)#EaDWITo1nl!sAP}^ zk_du^vrIWLG#b6+zJV>2Mw1ZiI6I&)GD|_tl$1qlLje2ih1mugmSuD0B0)WZ9O+W$ z+y!<+su16G#C%gE;HR7jWruoNaZc9LZfY2rFmuC*{{^iudtDvIcC3+IZVq)NxVT(5 zT6OI)i^DO4@pj|36JHu$ZMr-B;b`{|0EacQADh+>C0=q!=QUiNskZ~ftdENhu*#6j z(hRco+in6=4{vFh0&AW6SdIA$G~KclSl+p+p=8^C!+|?XGj5V#wb-0vr_WF)qZh6MxTvWw12~;iZH%v9Rr0Wx>?ky{ z3>LbNvJ%!d;Q9DfC&}zZ1@ufnpKlhYaFf+S(0df5LG*&I_JQ+s-Wb3j;Uy;fXv#TD z=3F@l+j*?`3G6)#FUJw|Sj%>URU`G*4Wuad$yv|}Yfh8co@;RHXzT_U=o&(B08pjl z?Ag2Fm4=YTYCo%Z(fxeOl^}HDo)GQ+LjOu`eJL-2qNMQ4S!{eFT=2uz)ywAaKSW9u z^GO0!j(Lr>n!o@&lruGBW8lY1JKc<+TFEjtgN_!QCQxlnI6#fWs~W&eBSNMP2%QP> zDGT#B8)#{!%S6l`c(jHZe*>>EC0`=-{0Nrbrs1o%>A{u>@Vm0g0x zBO}l25bwjeqd{TL^b$xValNo;q~e$e{JWzvf|-#ztbTY8L@|rgdmNAeYAKFOy{w%) zo-x+#hNbC*s1pk4rO$$qLP%x$^{UsalhHG;KiF(8T35_j1mQ`BKoBCnWVJY-sW{EE z>%vly#8Zn`(LNR|5TJ&>aA&tYLdIYHUdMd39H|UZcN@lTOG4E~`mAEC_kvOj_>A6sH}Wy~k}o38WLsZWF}5^7CP2D;Bvz&3*(` z0j}h~;u^v3Dy=hr7e8f`$5TjT5$uNi8bl|#zbg6wUDOi4I)3`+ z0>_f-%rxNvNMkp5b_5f0#>*RgDCnLOC37AF&JTOFHNcgoTa4aRk&c9?y>dYkzLdQ- z5)6&gNN0)rqoQzb#$o(zjaJnfR$YYy0T&2Gz8LWyb=h&ntoT0Pf;-1(7k$ve%XH6n zs_gfYZhA+L1D%?nH0JF5cA7nR{~c9co9|wFCd~Wld#9KteX(dtk zP{#YgImr-7QhRESCbXcJ-~J)*i}LUFj{Yr%ZuuK{vs_Npzl;Tn)RbNUB`dIxP>G;H z{An}M#Ny8_mgyLN_6{_f7A)aYC>31LAu`PJHjg>tVv&=5a)Pjc;kNj8$8wiFRB<#3 zL_$B6Y>a&lzcDfzO^`pjFP-f!zPXMPM*<5NXvKTDpa|PwH;FsA52N4Jl!wyO%3jWsBEi)WyEG1BZB)snn zLbK-G8L<`q;ZTy2KaE-8g(AolQ`tj|1uP%NmnwtXbyfkdK$GyrJe~|>RWQb;tNsOl z4DZt$hjo?w@|)#)%O;yV6eZtZTEpb8emU)@!zRnhwI~{>&m{aIXaHKVFr8!_&=^L` zT+*vEk?yy}^}-eaC|ZsuvL?kc9za{w3%K}!6wS(!80Xi^iCgL*7tqQ`VB>0Q=_ifD zNKS#aufL3yRMTM-M=HYtvzg>nKZ-2b6!>;78vH_-xr2*UT^&NQ769fPWC*ObCK#Dd zG)Jqy4?)=@B$hQ#K`Ej*dMe8V zMGZ3T)FBe1C1u=rqhZ*>?ycQaJL&0ViN*!M9bVg(i_@8Izh3E=dF6|kJ}^<# zB~6$4f1jB26OyN7UxntpXAHiYI$XMdf3b!O228%=TJWMc5lO(0e&^cK(R*f3~wYx%qAbBS2sE>t_=ow$VT zW6)&$jA=YK64)=cpn#-sUT+zg*lHQ?rogjQ;eNW4D%Gsa2WvW2W50E5aeE>LYNu<4 zQljNBPO(&OZaaJgtsK%`Gp^1gN~)<}YAeH{M0_?&5}>UGJg zCEU`wXPEqFw_y#D5>eON|J06qPfCZ{*O#@Sd17Ckxo|N{T*;zIJw0%u8b8e9cixumt>WH|?>&>dn zOl6z*jk@^N$kyqgt_VBTVW;IhWWOT7*Nr?!Bxyyl`3dOTEvCc)@QL&1eTiDy56y?) zwgAlEu3oJD$qLmXq<$4j5pJSC!#s4ZUxA?4?Vj!N-aU140aBtVxvKS7#Q6jSNG3F2Rz7oyp$0St2g}%OVly#hS6dX6zojg$-S?!hI=x@({OOB zsT_aT1fEL(l9UxkU@W-;IpP!mO7IKzJdnaomJb;N@3gEtMN8*(4QMAQuAna&FtIALRXxFu;*jvQEd|VvSC)B1FEP}g8 z|D{J;(EslUVD>qz9Dnb`K3#_yu5CQ{oTIi)a}^yI9y0Z%_GyFGs1&&!`r7-gUP{@S zP%Zj}H@tLn<$3bDQ;W`H?YPnA%|+$j1I@#YenVz%1B#xXK9S)?i*L1t#C5WUV8(#M z6TFn-NB}-Fb86If3Wr%OdpCNc?yuCj3j2%J&HC|oR|Q3=zb$`BE@X%8G^rH-#!%R< zO^`_?-R5p-RHB#kNDycse9Y;C!oFhB`mbibDQdMotytVCM_nl?yU`?uO1VyJtdET9ih^jIY-W62N~ z2Huh8BKLk5WEgvN8fc+GcM$?iTFAB`9Qqs6{DdYJ(qZ0SO^_H;K@0TuuqNGK0n@Q- z2iM%HKw_fA+=%X+>A;`J9IG3nJEq}3(f1UsF<92(EwZOK+O7=o`ip`tISQp%)**>` zmluRoVU}H-=eoDA!x;Ead$*dG5t5v@);*FpzpDs!`F_RvJ(K!QZbv)9{bBq5-z<2H zMJZ4VU?3m}NFX4#|FQ)yDsOCSE@$oP=E~sa<@Ue8cb)$eeD6s%v>jkV8{YXs^Ir`e zSg#KVW$|m0Q(Apib2#`5u~xWd9rd6`@{)bK?WqXf-;2j)Q&Sq z%{Xj|CMj*Vfx?56mSdzvYnBE zfM`U4fLQ*EZ@0HMwlnlFHMDoNbp6k(0$l52H zh!V1J-{=&%VM#JZy!V}bTrkBP?#D8m8>J&JiN}`d6iyxUEJNilAt(D>llzi7pe=O^ z>_X@c1U4w{{C5WnT*JV>7`y4K6{= z3M`03k3lk}7J6cDoTbi#qnI#;wRi7`g}|s`g9%b9XR+VtBaBoS-9q6N6+D?hP?z15 znLtF|xtU)61v5lsq{kC`{02*==%=1w=#U4!1~?o>Qv2W+WiHHU$n-EvkQ_!p2L|uP zwww;31v96b-0|LlkcOq>LBYsV!FHvILW^)IshMuauDRY3rBGQ3-fq)Ms)0mvxeny4 zXk=lHgAAQSTf>ZtbJ+|m5KrM3Im8%ESj18mPVO>^Vp$E8^50aFsUZWg)k!vh?<{jkFzQFMmDSXW`>;mCy4m$?J}Xle0K%NMTYSTh{AI!q-9-{UI5-c|seN7YzQ zDXA?b8E=y)F9A~rjya6r@Np^^mr{eP8wHQ3bs<1J1cO}V#MuG#rm||gzmOVUYAL9K>WPj!U^)FL4$`o{iD>_7G*pw4@^W^PC=966S@dMvmE(+tUw_bq zub+@3@-GxK7>RRECoL3?l%!Zi@h2n+YD5%>NcKhjeiP&j>8~Ku3#>6`K!>M@)hI@Jl7Aj>AQC7-%lk} zIV5NiebJR23y6ffbEx`CE=xiYrK!5!>`F?x8VNsg!mQCS0@8C!3f-gjbKFAXr#jN* z1l9o7vCvjqWpVI9bB2~Su3AlaM%X7B(PPOh`w=(&4I4o}UZEtaEb$9m&m)sDQ!89* ztHdH`hpgHbz)zmFi4&U1&1J|wt+oJVR9kkcq$JNbG!99lfpYz>GT!cWOzbKA^|m}Z zC;snBiV!gf-`@c|boz1v*o8u%)4uSdfjn%XX(>iLzt zQedEEaor<+v*BX?0h`pFo)WmRsaC2>jXi`5Y*%CTcE|$Otm+p#kxI6?L+wf z9@a#^eI;u3OOlvBO1rf53$m1`uBauKl4fm%Qq*B zqx^^BaD-bFCZRKsFA=rs*CJd<(|>7tOmR11V4=5IN2ZTIMpCYcN~-WGk-Ex&D2^=W zHszOas1+#cti8oT+^Ju5f@&YSG}e#g6A$EKY32jRWW<;w23XS=^SE5PB2%)BWha^s zX?NArN5=@kFbiLE5mS<7$6*cgL~bEnib6CmxK?m%=W!!dY^v|(a}t(S_mxY6m}-)6 z7so5%@hqgBsOOlOMokj08I)3k(Ag&#!&$~Lz5M7q#GR*ZQStaNPu=Z8C}HGdx?u|K zn@0%~LXs&I^l_+;1kh=f;(iU>KL}SEyIq8XlQHWbTld?IH;gaxO<6TPAr@(6 z$vJGqbTHQkd=w@n6@kHps)I#=lrL2jI&vhQ7^%g~kW`t5c`PHX2=i!1qaS`08~I{I zBteRUq_6@^CgN*^>Z{z8{vC-BLn0ne_`ZT-weRLTFZY@H&i8+~>rF@`M_u?Wv*$rs z@@uZ1yFOea1IWSJ!cBoOPB^vRe=2uui}8ERiMCgo0MG*wR`E-*8kPdCVI^md#S&CB1^`vsh2i~~$e`VMlHQuefMrI=zH ze6B(fbpq0jXWLE2mf`&jC64@T)OWri!9XG@Q6^fpO5Lc z9`A?{@YodN7O~fE1jjTaZ<+|i9I(P+lwwA; zX=q0&RR+Zuc>%{PMY9$zh@j6Q_w?SEW=nw{jfHpFhjHzg?H>y znQyoxTOjhAPSz`$vc8yD9V{;CKP*z3@+D6U@NQS*# z6q}_H%SjZ#d>acuC!Hz!xKH{s2hwNO6r3({&t8Vv4uXSxjJLW=7sX{uT>>IVZX@~@u6qEGmvd~QoD-(1snbO zx-!PvojncxiFCo|7k?L%QK~q96+8qr&PMU7p(f?K6A%!Hil!YOQhgDFTIy=4#EZ6B zRGwNqwXIncYZ7)BjDxKL$!Kf(sjr>wAJ(lcs#&qY_m}OhF`kh%enQq~T$FdW^;wwx zD39AQ%$tv!-Of$ZDy&bey@W*mFg*UiJNCV%7K?r|j~NOy>AF;HK#lwcW|*#!`+_f7 z?dNrgji_g$_?7N91}QVf#|anMEAZW2D@u4xymv057OXNWz%fR#N_eI5l2k5-Nw288 zRv$U&b{3MG@GBt=t)8aLR=Z93GMGTnX|BU+Yp^TQmvhRSrnA7tvy%io7NTO#f2dWj z)6_HeRlB#2Ap70Dw)fzS_IX>K20{6>v)jp?$0@0?pR!Yr&ukcl8h=*rc8V*^@;5hn(LGUwLdUM_Jk+$Hg*z$q@p)%ILR)k~KBWr(s#H-=Q)O^b zI~*C$iFuiWOJe96O;?7!o>#dH1kuMAx4Z2H%~A3VR9K0raq05C16OB|TT*kV8KTZd zctRW>br%j(4qQVhU&VT-_av#|(&sI>`WX8)IVH#vauR|HKTn4L1%7QSAHwD*L5139 zHXhae*dPT&zf}IlFWl`6dtL< z9`ud8XmkipTar%mmZ)*wZLg>>Bbb4AiQK;KwP0H3h^R1BTJ3`i? zXNkujNc{6udozRi(C$3WP7g&4}ocwFpx< z70f^G?>8l5`}T`)Elth&CqGNbM-NM~A@l_iPx?+nx-Tbryp7(17_|{tEysM`($Q^x z;Y3pXb!WRx1@KX}z1RD71)dI=lTJjT(rd|l3-ZU1(v-5#K6DO(N-TTv2sIj#c!2@e zvRN*DAd1ZxsJc#Rk=lt!o#q!du6xPIwBgF38wH%AJP_N&rIIEBYgLZX#R7u8#l!n2XH7rV^k58Ly%~=LSoX#MKuP1bx zW7QWNdZQQo28)T-@V1ZDfB9vP>Dtzo(W73E`}JNXBA_rLZn1PM@el-We&BD`XW9kY zI*w{HHE|ht^Qh5-e_}31%eSCq8@z)USk75PR6xj5e&RX^z*)C7pqZWgkz<*w6&X40x{Px7$bb1 z|Mo2{mr5}uJjAT$E?Zl6kgEz&wA=fn0p`#V zbizuJSM#i4!HvHnPqSNpP9XH&hyQ&y0xf-m+9o{E)qZ@+ZzB#A zFPuFZ$|@tFXgV%6DRl2txRF@4Fm?yc)k7D3J``LV7vb+dQ4`E6n0-BoZW-E$qmBuQ zhvNv?I{&k+Qv^^y1D@v=W>ePoc5ufTBO69X`~#co{!I?cDQDp}i*_6D1m}i(J3XvZ z1{(w`(ZyO_Bf?AsSN(c?CJfm{AyccZdHPwSYcM!ln>vdK_wb(9`@Tkgrugu^;w($W zv_&0xUlq^~6pX3tnY-!$6N_odfc)b=0Vohtb_SE zoef4!s*ec-!TPL|pq_QP$NhBF&pmjISP+$lSvB`&TfdYe<@se!&a7j`jQx(mHpz2w z9{U7XqKmi8lin|-Hx#2iPWyS`3-CIM1w7~2we02F0k6!hGp*%(P5P&RI#ed zZ~Rh&Cf?{EFZqXg1cGq7MqD5OS0yb#gJ2@(`sg!1MgsZdGQr{|uHq8}G-=GMkR{alaq50U^=8+B#mtwOqwv1TvS6iGb4tTKo*txMa;=A6`EgV0k-S! zQMl#85Q-g6Ks!&rY-?up*A}e+LdCh{z|Rd8&d_bagBx zQyaY!-we)F3wQ(HZk|an#be`pSLoZSs|eUxwOp$Ac-%UfH@at2J?|wR;jBV>rwO<4 zxtb;+SC3B^jP}fJO_h+$rE*rf8NOH|crz%14=`Eu!QBQ5G6ExVftnDZaEl?f;$8QX zl_pa1&8JhTdtK%34mwQEmqVaQM_{& zNIx|(9D?gyqcr^Ndp$C&Yh2k%c!pHuB*ScAG~-{`+ZMdsxtH;Lw!AKBHWGx5Fe~1~ zP6uK%@#pkn)E{3~kvcj)Mb3;`vYvnH=9CwdAc}L?$==iF-yaFBeMA38F#*{h=FRZ0 zhyRh_zb__?ovi=!MNx~ktz-2V_V>(htRuhGp?eC;Ss8ovLK#^mX(jvv5Csk%9b!0B zU!V4Ny%aCaw;TU$?7mgvwmKVX<^u1V7wj2`oMijf4y{^Q54?hU#=^jN7PAv?3^C&j zrlyG|c*|6lg-0$6lsY4BMz4U`|6fPMuwcekp=nQqu$id$XG>`(t9y?fO^B2V|1qDW zQ;Z?@MLNnc@A#alQju+xq7%nL3MPhinc?756w|(svcJDH5c8s15snVT6WizVMLLTK z*T#Vsp&?TlnC!KMD+J!atTI|_Os1G35z-Kc#-9LEK^Zqn-dfbKhm;O$V51cuiwr^n zj}=ZFbMpqw2MZbDj08)01-yq48Lc*mlR~A%(LlZYB!^Se+sY_oXh17Y7CEnA^CcS# zT1qS3>w!5pGCj!uY#h5sf<6?*Z$YQ4|}8GDHm~)ZMvgn>N+)ZljUj7GFY(1y?m5DT6a0V`mcds zaa1ecC&69d#f}c|jDacfpO`53oceS>&Z?WVi_~6eiUv0+x;|B%W!WNb0*sgmv;s26 zS~^Ant)mpnEl0ppO_3?q@qnwjEdTyG`O)?P#jnjAt?hiY!-0Fi&;`hp8^l{(1Teop6G9wyKvDp*Xl@y64K*1T; zL$>AGBC1sYY?F`#eue3oysu1EO1RxgLR1QT>0RXI^Tbf6C`5Y3!Z;WMorRY^(`_hl zPeOv7je$aqtgB5{vn^`6?j*b7F6|^akZeQG-+osHbqYe^e>>|A9n=QVGieKbCVxNE zQl|yJDFUSmr;FBK6i^<-vhfZ zU?Z3#%vF!YiVpX$vOp==!lH`(ma_$uH0kuOttYFm&M6}Du1QUlK_I(X# zkFE~+X8VSEO~c2QyhOZ0l}XW}(QT(H)=S?rOD$8v{!4cP>|Q&pfgyrL8Wke1Z+l=g z`A}TtP@f3_iq@=N)T}B?POa2o42~7tOs4FmLv9qOL%Fr*(|Ph9;m`k2dpCslY>$;t zNowu$GC~ou_@{)-*Zc$g@J;P_NO1LJ)cniX5_AE)=i-DBRypNRarX9f{;?;yaU;OSjJ*?}E3bK1qHzs|U&T zPbl#MyNN3+LzdL#=V-i=y^@!bz9BxIGs+e?F+IGbPBnQJ#Dl9lAKrEq`zr-kJu4FZ#+bpIG3>WUMgQY??Ky0zGTPQXn&w=WPMv zNN+7=>DFDjpUIKv*bRyU1?FxnazL|ZbMLJPs^k`=i>LAL&l<<~zH9!18Mu+FTqedk z(FgXKGpaow8Da8yJ$OKjmqd-*wwgT8SDkPhH!hL(^;h)*#r_`~j=ZTWgA=+mcaMVT zzh7yCk?-1wQg)p=qu#(7lf_T{dYs^qe~6LHO*1H;la6-069{4i*5Smz?C)>eF1x1C z$0;QEk-fEst)|E!Iy+;UA*Vsg6=wpHN{BZ>js?f6WJz=QbS8+^r(1@p56Y`m!K9^w z!twmQk?NRh8DmI7iJwi(3o77bysmI2P zp3>Oz70-pzMI#5kpBD{RSAJiX&rX~S9fPoJV;wxmdL#<-+01^Ie&&qgwl|8s*{|)G ziX|wQqFp8AYLM7PZ|_sdgWjS5gw_DxwR7kip`}1NblDySXrFgoa2OWe9< z+NmMxI#KE|`AJNYzlZu~`uJr_ww4UgC#s{i^HAzN7>E1zgqHCKTLzgw2MQE@Db3j} z_klJLSq7DFkMwPQN)+kXEq+=EnqDGpM%_+O6|0u&W~hM=jgJK$#c3uEKIFtGN#p;l z$47a#8T3hLupxZ`aVL7$gZcp5gxg8t&7)5`;|hn8y?RPS7Hx${71BqQ$`~9fxQ)vX z-x+@+9^NOBC~hldP_``MCk&~%iWgR!!$8`F3zKc3kFk2wES=WGhW@TGK`FP|81q9N z7fZ`DgUNN`N#m_Rs)(6{c=DLusAe7D-pG$4070pcDM4uL*0&YJbddl^SN0TK81y3d zfNo;_s+Hu&(E@sZyCF8xtvZY@uMZde$BsFybo318M6VtCW#VKrBUGf(e@R@-gZF;IC zmH7xA2U3DO`I$*vjU|pz)5d#pmXOkOALh5`r|3fVNg|Jz5h6Fc$6O@RM=F34_6xLK zL9^Mp5Kt@jAE;=SS36@I!YUuTT`+uDy8?tjz-M)S2f-lk{Dr~WIO;<1e(K|!_)Swz zOPB8OYc)BQm7D#dr4O5SVcC1kyWy|f5rfxyP{Yei(`K&m)Kj7*Bx`#=Se0kSNf8E-yItzJ1Q zj=bfYTob$*;k(0lZn#qE2oMbDRDZdBXPM(HZ}nXPIcJTHY9XXsoYGgrjluBAesm#8 zUGq~C9O*!UP@@J5Ru9j7m?nYh6$JBE8>{5$Vy?83;`fardLbI3Ta|-XV z%V7!f;e6ZMpjlaS!p^cZ@u5FZt0S@W$74+ddn%NY@Gs8d$sZ}uk{M8NdedX>!O|e^ zXtT9^!x#h-FGj=+x1bfgi?IK6>lINQ+PQqqc7{~ic$vbLrJkR!Ol{tvkSP4Qv6$F; zqHVbB7znhvzPkAR1M(k*`4=^l0?@x!7xsVRoa4Wba5)&;oBuzO_AMH^svBHr0WZI~ zKpDe)g3BByAB7vz#Z)(B$gy*--1tU3gqosgZ+Bj#oMniD1?&k-v`?P%Z}d_Y zO&OUy1#$gdH~N*CgC3d$XZ^7_C>UXzz&dTF^ud)ieasqw%2z~GThv_*(%~33GV?R zT~*rWb=5NMwo^R}cXM0E_yOvtW(`b;oqvJ{mdaWsYFTwOwhRe&Pp}L^Z2G4-tzcAt z9amj3MKVaHEt?0}U)NTg^m7AO$d|`XNWyOofP86lZZKcmqZ7gD(7E)~%|(Plk66=3Iu3WbQdy(| zg4wrkJv4{ygGr_wCqt-(B4$07!aSo>MYIP)g25VY6Z64f<#^1W3rr|1C(hKb$zq1A z$_i;Vq-J6o&x93BjT{4REe0m1%6yap0yqkngFrTBhF4_bkpT0NMg?~f`DNvpf$uW0n50*(2y>3ZVD!@_y6^{jKlg808+RY zw0>0}ovASwz%f10mVz^*u)*uIdz+}Xz&SHFDbPbE_z~7opxuO%FENYLfumrC<7hMqlN*MDNe4lwDhfQm##u^T|zk(kBm&4+_hi z8n{kxcuslp-=~75;NPO$zNvW=SlDk3^`G<8!B@4|Hjxu6C+clW?Tc3$gGN;gj8-gyi^S$V(L`cu z2Q6=`=7th>d>OJftC@$NC$(7iu}%CXX?9XfEN>Cka{Bav>x+&#RhuuLBoGv$Y-(aN$Pggq9rA-qnc*zb z0qzp$Vg!Gdi|PIAOVDFhDbmGJ-|jx;D+ltwH#*G%Rr^Uhb%jRvsAP`JBo8l11is0= z!dMAY&;l6>HvgvPmVXR1ulbNQbq@MYGUrp{6XAZEXPDmP;QDc zO3qWwGoRzix4gdE(_p0W;#k>Hyfij4&wcy*kO|Ws&lIB1SpT+b_(xrJ(3UgTzF5#t zixKKZ`^8B8M>RL{JuzS$U(ZW%JMcfwTV&9LxEkz#fmy@^l;Tpu>~Ql-lUL-LO`nzdtON%NES-j;A9f zB|j=ACaPJQSgK{N2{!lepwaH_GVS42;AT&5$J~+vN$m4-3MO z{Sg;S8{qIA_tr2-tWarP#wX%43{u(=w8i(APmT5?znXgu@}K4#AHyYvmP5jd&5JJeo_A} zXmNo@1XWz=ZZE|1u*U%ji(`f$BP~b=cL+ve4wN2d<;^K%IwWbCbapbK5Ynxd@gWE>nqij9J$HkX{VW*r1(j|&u2zOag-3)XPKSAMkA&2(f7vjc39bdWSQ%3uh4%GW*(Cr{7T~dmg1Qg-l2vd z4sDp&ANTy&vQnzw9&K0_p`!kBtym7u3-vC|@CxBmpe~xz>dwh3T-mSSWk^P1aq-FnK{{9n6vX##b=w(Ed48{-{a@aBwE-Dt?i49;HZp+ zfU9zz?jF|s0IFqYrlPqDCz=rg*lj}hj71o`&OoBGXLbrBR5UhLEME~)%8+Vr_V-7r z5Lc>dRDYL%)R{oz;o;HYPJ=<<#U)sl86@7rIS6c4d4=f=AG4Q3IuQ*KFmys|w0IbrFiDpjU+LEo@OjBQSCmtf|9G^pfx2*9zaN~Qug0ISvkY2ih z^a73796URk{oWTkcB&zRxcZ9ZKGPt}rfoNxH4N$w{PVaBRy%%@99=fWi?67!DUjOl zYyUvficGCzFhyih$j!L@D$E6dKmgOj@RwgidZJ;NM71epbs-*rap}JK^+f;U)k_m^ zeQ-VTUpRVL56aD-D|MR9{Ul4Y+<&|JN{(0i+kR|+)GCx+l;P)&X=6(G%3jQb*SB*B z%g7YZ^Yf7nBF#b0AlJvvuXe%$Z8s4=Hksc&BlyZ@j=hJ*{vMLNk|mWc+8X2JUPubb}Z zB6EwuKQ=T}fcwc;bZac$B1!F!}Sw*OOvmZ0ASxeL_I5t~$64 z9MQlT?K*%cS8wYhW@Fz7EQh!eDIBQpkBmEzgh)#y{iPqskC-p2ujUyhLRF2)1SrO- ze?otcu5ccvaWCH><>&>rtWc21n`SIg_v826iTFW+B_aRzlhU$AHD>C;``Fwl;y>|c zdgjsR7W#@PyXRH{2lv@d&PvRqguyq0?GKU%(~<_66_@}tUuKTM<)hEUUe=9Lb*mbw z^`Ot~;r37AZY0)&F7GnT1vQqqM3m0Dh>zb`eHby+1Up47cY9 zf_9lYwQyxIk^)jfL3yNbh0wH|i0SIbD@T@94tgPvs#YyWzEWg0@7+*VHfN` zV#~$M=nQtrr!`_f-6kZbB9kO$b!H!uWJw?g06N%9H{Ac2&qWm_ zeoI19Try-UV(-ZdBhB+$%0>{JmBmsBYa(D|DsE&gHY zkbAZ#zGzpVP_#$Lp>zH`p7>B;_!vFvMct;zao{9q1BPZZ4Y8HhwNv-=EMvSA2?7 zms|AxB22Vi-$^%ZZd;kTh!$lPL7==MGOTd}XTJ;bCJSYlK_&Y+%ySg)gFlOFH~74z z(R??&Y;~wIxhXTsGiUNsEm<+^>fi>%Qz3TH*CsHX6D*BK3&lfF1DJ@)8ozifk0teS z|Dnvf^+Z2M4e%GwAdN*%^QE1yd~Dch^Ate$dUCrLv3qP$JzYR@vBY4p#@T5dw|ayb z=X6J!Ywhxwut+Va{H^Ox{>On^P^6pZ)}(1&dgQspPG<=h#3}H4WV+7D-DBd7;FuPE zi0qKpt#)Y^plBKV1y>$fsk~1>S!==2{rljocpA6#K-_&4dQ_S)(2m$5bPD;plg#1~ z?Z8w1Zdc7Ij?e>*_3%JS?Qh!>G*EYHoVd;1l^oD(>YNyDS(_CH5WQs%=ME`ZqCD5F zNwOF7dfLcd`uh?TTsTvBYNoh*;3^OO_e`D5OL@K*@Py{Y)4#wToI5hbX=x&0yYU;j1IzgY36r(whJ!Y@xrsvmad4V7;4E%FCUJT! zh?>%1CAq)$>fMv9^P-kM(NJ7(zSa>;p%kry=Jn!xYUz|IJN&pOcee3Oagtmb8jH0_ zAmj8feYGlXMwEbnrTa}UBqqM|7K0n{VurF9(8P89ylEShbt3&>W0tWDZnF2ppZ$kw z>L4{vH|ndYO1svWgs{J=?~kT8P!oPx8N#bfpuHH!qmF;D0}XR>s^y2s(Q-lw zTu<6?P)L?qIF^HmGf-a;aEuXmh}5_}08hGfur4aSG+I}CBTD&ms^q|KkM)9gN&P@f!-YY;K>4RQ9cUTsJ}}PFA2M7onXK0 zi~lr-5)=%}(Y&7QQGV?lulYSPx>mune>GVk%uuM7Xh7NxLYNcJlNP*7N*fT1H;=e6 z73iOjJbR^X-4=*Wx1*~-R#i`Pg~POpVyhRYjno@AuhIqyGt(;&NgPsE{)EsAFSMs( z+qV|c93;zPA@NPOgAU~TuDCF8UQ6ktzW(E}z+VEP_T{ z)`j}XGwtN#V=8S|*BmB3JiNK=h7*79#erdKZ12ed&#u#gsmpF^eYM2w!_ zAUg3qP{(D6nRUCDB%qfxGp3q~59ZVL&s4o%ip+>7%)>&uMz+4fMRxg8r>5Z*zhI$A z$q|=wAxq4QC|ox$6ur_xjIUR9k^wVvxtbTxutK;O(P$e?H&AAAop{1(H<`y*xX)5r zhu|Y?@2Xn71ttEYTnvG<98qJyNG#PLlMCaPITk-V;<86I_{_$JTIB%WdqO8na5J;!4%*3l|G;mLDCAvZyh!7hCI+WOcwlbk=K zql*ds^bDMGwBGM?gg1RCmfZrG;A(0zxRmma1Oi2Go?X>tz*y@MNZ#Q1D$7|norjuK@Wl9aZds;6NJhE zVfFI;9mQ$Str~(&a@Xp)2lf;aSMk0!1pRjuN@_7!meD|`*$f!P=n1KUK(j7BlGJbZ zPYtOIiy*P??b-WvW1p>a@kWUA61K^}?Yj>!7~_?X!a13WC)wN|rxICq<~;e7{NP(@ z#_U`+TQf<6;be@Yoi`vhJJ6PREOCx~9U}I>z=#@LITmD>B{@XwRY#g*Xic1Z!Jk^T zQP6g4vauVq6&0!Wd(3GV8A2m69<8ITENduQo09xyzB%2u78hydcKRYG^O2VWa*%DY za#g<(4>No1+1R;ZmUqW|K=Q){oi3R+POUp-^he_JMFWJ%xe_s zSRlr%9`hT%PQug8J+k06gIV5F!>!-KlX+3wlyiN4FZ*mk813L-1*AH@zlsQ_P9I-q zxqM0;RF0(DFG&Gs$*Kp@t|-R%Uf%`|KXVWH{OJuTC3|G{CCxxwRKLilg10KPhgafQ zZ#EA1CFf|v-v+~y@3T^g^M;&ZC{z1)ee*ic&b8^;omxOJs)*WK{r-DE8cm~|#BU*& zfN+eNn`>-KF$I(0d9_C@fbK61X8pt)8o|?8{zlA(#AlJ!BDDr%7t~-VFI)vr?nIZ$ zSr|>%RR8O2UFHb>K*I0mgOuqdd~IXVx}_;hXl_wz0^=){5j(VV_F*~tYO~2I2ny-V zce+gW+_hRNht)evac|KWTl3`EbskBd5S=r-Ni7X7rkU2?Uiaj)4wuy}h@8ISFa?#3 zr6-Bes>CDDevVWBR=Q#(bu)(uX|7gBfSqe^Q|fw$w@ct1bF|UXvBGhWJD11{%hYiw z5lkgd`R=KN{%8-Z#g38LCGo}4ek;I}tCh19`g-*^o2LbplG)Y!tBnI%-LC*7%d&ezDzJ>Fi-P(n;vuaXs#(wDp3xNMmF6%FMJ1GRJoVOIbB=&OQ* z0)O0>n?mrK6e+ouHNP-V#Jicc!m+MWHgzyQ5y8Q6HB`|*&&f>QhSw}wnn!>VQ~(w! zCUTEyR+(=Y+T1CtDB&@tBm)UdWQcw*?;mOeMmmr1GPqFZ0DfADc={iNtO5hxJWGDM zq`Aer6%&yI`&3PYnY`=2R4kCbwO~e6zwu?ZdE00#5N+~qWe3o^ z9rDwYKIL_uU-a7Br{!q7_Qx3{6dytFX+8I*i<#HC9W zC$zGi^S4H7!2&nVI(qT`2Wjuv9$LFC3CFf=+qRvo*tTukwryj@wrx8rcCy0Gv)>PI z@AF~zIo-cuUUQ5ZRd-df?e-WHbD(+_lr7t+F7j9IbGRktpx9b|lLuHHdh++I^N-Am z+j+rtebzj<2Jo^z4B7$OuqFR91%J}%jMJ6Jk&8i^c=*hq9op0@ zg{TqMs`stqXMU7&Rz0PhANw+~pLyyna8hD@v#q(`=L4BGu$4WYCWfw||0=L6&$lH^ zJ8B60N*%DPs9M38VnI=STv~}VVwcL~Z7D)Xtdu%eOl_SkD)f_stvO`A8ytUi5=FfV zyDSr1A*iB^Q(0abOl}YJ%vb3E+n_e}|1cmC(ru&HOalA*=47Ilxy9#TrRK?f^>cJr z)lgok7mfs7qsBnOsc>^wNzC^=8)K7mKIxeGs#W>7UPOJ1R zh?6!It)LMjeM_TWkdgGOPv3FHYTf^Bi?{6YT474W#+<}0t~^#XDn`%LCxn8>Ic(Uo zR8Gpa!2LQr6y}J$Kw46O($Xk_sz6atmTHNH%$RX8-zyh~lNym=YYJg$D4sJRbIVnq zxf*e@Agsd~8A61~)SY*ToG@n~MK>L5O@R~i1n z3ArBxP`WrtI+L>duv}9I7Het&6K_{oYsOl?uEx9KFsImojad2SQ9~e}P32Kjrr>)D zc=4JL^OpRN&IcV{uA+5c5k}k2d8m_~Q z4w=@$FCXOAW}066efj6YjRH2rv_f+sQ!NXb7tHHhL2qx8Lq2cwrhqWYujsV*^xMa1 zoreHlhePqls2dawTT|1^ztjU5N%Dp#e@#4v*R$ebs(H%RD+4J>)3v^HA&l}&y|uw< zbd1fC*P6jj&VJu*+&9toEi_2b%?F7R`Z4MF8VcD<>^OCZPrd?s%!<4z(24#%#At!v z`MP(C`!G5bZq0^+pVt>sMe-!tHMR$x1~LbGxGpU*E|B>#L-B$obspA1UQ!A}a_gtI zlkdKlr-JD9JMpATLTe8ofsxpL(yhtQB2Kmzmb871lp+(*K5IcXh&GH5O-`8Uc$nw< z537>@o`M;*sCmDQJdEZ0akcHKckNdk7{agSC9d~n|3QCyJuIeQ)f6m+wxbOOiZeD=a#H#$ntsf;g%17)&}%~H-7>A9%Q6#8Hn`WQGs&YKHHK1{oa-z2ZB zqwqS?er>u98GF)!*7-9WHrM*GU9|cs2Cx~2Ap@S42`Gg-@c!sGtvx9R#E9~l5(-k( ze+z60Llg`e0Ge6P7-I@%K|;Kb=(69t>GYoNS{g!WupbID_w35$=DE4(B^Niy?~pFk z?86jCIw;iT#ouc9_j_Vx678Pa#6JMePkRyKN_K6dyj(^+qVi=NcOb%xT zn-V)CD+fNG{9C-r(Z`ti1~TpWRx0B=f}xKXUN+rTuL(2)+C!=A*}{`?=_Xj{1*Pnl zPyMs*bD(k4hS!|bIy;}LM+5A^ci}zn3aCx4vlhg{)B?4k$vbJ|_I-2ZB+gsy9~Xxk zZ`dPYIi;8C5_(8jKc6CLvzUcPkFzoiX+|X_0@Q=lrE#ev?v-X+Rp{Nb2?u{39#Oc_ z?sW;m_J@9BE{9+0n-qkoohvHowMh z>6o;>TkmauS#*gnm@Ty!8kc`&x4C9IX;&brJIigFV2Z(stcu1c) zTu++JFXvz!GmK;{miL1p-#ql63~dN`gig)aeoL!Dhi{@YVyYT4R|Wgy7s?6FupO4C zshL!S;AQ~E3yb%d$%*L1z)(*1hDOoFG?$m7Vb<&G}NzU`DSvnF$YzX388OkB;6BEM>v8qiMtJKOnp^~; zAzwp;#xcuC?auAw{%+}3`4{-#b)oaFd6>E%UC7Y#zZt&szqxIUtS$a&y*K(#;X9YS z7C&JsjXz;3WK!#dCQ_+Mm1>leim8PJkn|`O$AqIPQVj%-64RL=7y!vrE?vE!E-yG3 z+9)KG@6UscR7{XlkB_WA(+R7cEw1$&!G^xrO>f2hzC7*^MoBrr0qi*-(kIn}`okLJ zxhtAcphd2T&>lmB+Z;LQO3}?ps5v1@h(g*>7w7TXZ{$qcz;@{cY7$i#qSzyU7NMDTPqb^t_ zi2Pp&wLBT&Lt4X;YLm(l>SaU8Y9~RT248wwkHV3C*~gkT^%+CJd=WG;^p%hz0Azu% zNVW)~0Rmt<_sjVOWc%9qL&|VeKoK;-7|jxu9Eu|Vy#-;{VRWT;MEYrZ#BCHNh6_>i z@?8bh0=Uo%b^j_37KWEsz|wC4Vn5D=-e~!R^}kg4-fZx?$gPiqvvt|4ce*_l+~n%P ztc%t;oj-zCFY|_!Z5!X)(l=W@RmuAKYo&)BK?m@(*g^EuJianS()pM9#j zopA+`IdxvmoGo4D4r*h=YP7N&dL$8r5 zi~c_RLdi;nF2R`ADJe z8!&(fKK!rj^VdMYsgE&*LuCjJ2Egcsa3^LoI1G*^OJl9mj>Bw@?Ph-~Z}9yNE(dIU z3U?n^EzYwK^au{(I0bQ^l&=doYfXb}B8k(i`o-ghXtRn@{AZtvrx1;m9);`8s;l0r zWy?(nzeaUG(KSulj^Vc}`Gc`HJ0^XRhw{gWR>T2%QV0Mvb10@;nk|8MJp;4dfZncb zVE9)t_Li*eaGp^;Q&eLt$H;{w!i3#n)|2&!Fcws`+OXW-nrcAZuj(B;)Zpa~0>DP- zjq^xZ*5#I)GH){PncB_n{5-gti<%fjO-u6o3E5xlAaPUc~ z=-0dZ^ZILv(M?47Y?YrHI4m1boM~d*H8; zUh+d{N>+PmJkAwSF^^EId!vDD;Rs!5XWm^J4*978?7;j3bo5%dqWA9V@6om)w^$r$ zHC0i%_z~f+_Xv8`pAu6(w`>F8FlX~R1f|w)6GgA_$Nc_p+|PJC#X|@@@M`IRM7MlM z-$#e(1}~s5O$g;LB`*>Eot*9l1ayBsNn_d%7QJR{ySZW72?(J2Gl0V48F`Ws1Ht;Iw za`>w|_wqrRqd7)u5Rmv6Fj6H1`8$QG--E^fh0q3VDf?PG3?1AGKI`jz7#ir*um{RP z&PrB}1kIe=r6v73tk=#*1F!S!hP#_njbwY>xmKVCoub+swnhTz2zvuG7rgfuYX@HaYN#V=K-k{Lso-V zCyQYK<3?wa@kHwCwKDG9{|zqWaBbHeGHls1H5B{^c?c6?NKPHS%?k-7HH**ep(LvS z8xr!AMg~s6DjF_7oDDr9+4#6~#C?!Igp9^|c#{UjrL>ZYoE6(<`)iahkpW-{jgfFq z*}anlq$SK%_&6j6S3PIXB5+iGqt5(0_xQEecd`C);!!OAVhln@;$*T+A1VTGj>66b zT5M#lSnwKmuoFgQS~H+w%$tVRcC5jyx)$v7TB3l%Qn;SkoWeeSu3C6^FG_yibZL0L zpAh+mCj9ncnfm-$<4JaIc~Rn{LEaTkf`>!7rV`mkQ1Fc!0R}%3e~D+uqA@5G@5Nwa z-w9Y^O!B2fHNYU#F`X8<-hof6E?Hxw$IHv}@?8rMIiD^z4(?GuFG-L&Iz6y`YXn00 zmuED6OXM63#CZbZYue+ba4Qm6*12U}b7$lRPsF{Z3)FHkKYTZK`aM#j+Y+rYvV+1eAXZ>IvTfO!%{A4b*R*ZUxKX4O&yCj~ zPCM1esI-^pFx*8vXT|`Ky*}V~XriA;1!9K@*Ssp3?44Rs<`JKk5*53m@AcpjeTJdq zdHifxvlkdlba55?BZK=jIAbULK-`(^(d9ruL_GJ{wpmt3{y9js}1WBhj9|i7O<=k9H`0aBnw}t6RNF;zoMKVd^qL;M9n60B zWR@blf_3cX{7=V_kSl>~+v?cRXuN*Z#t?}D5uj#u6a=p%PoHEmIsc5iS zvE7Fi=w1omF?aRR4Z%{=Gi-pszB$r7f2=tS(6iws!C(8brQ24{Coq>5p^xfV-F}%3@V@z z8Yo6@S&0)eZo(Y=xzreu>THtNB0vhPSnJPJOGw0(z91UUL9$jHXa-NjsZxSOQT#|L z`vy9YsOl!ak|Wj26w?9~p%gI_o?%qfS8y3=ogRxzT>5U#^ey5N;Ita2)@j|I<~2ps z_>4NF8Z-a9>G+^s0*z{~@jr@^S;j-q2&RTTaK~??5+IIAS+a&#u6Qet(Y82M=?$yj zsMajBThZWZ2&AS?8uC?7*4_DBkcko&fHH;{(kX$}%INmuLEg!~#A6D))x!LAKbQ3B zH9qzDF)wMYzE3mjkXy99jrYr1^_Q~r&kPc+=E7x|nd1Y*HsCP}TKAPm>4H+S;ilS5 zt`e>b( zk3E@^HK+mOP~DfV^-d zy9M=VKq+&A?G?{D0D0`6ptD9;^9N_7fKnVZuo9#1WTOa9`PdPflnL;}hRaZyk_E-; z5)5N6G9kb;wJ85W*=}eqs?&5wU{;cwGr3c%OMDY7jBsfg0_UK5lM#RF{AKcN0xlhC z5p6=@u%+u8$)k;=uLWg2?7e#b?zi{3qnk>os|`KJCiv>sFRq=v zA>pm`lpb9+CzMDtXDUh>=~Kpf=2D;n5e@kf`DFR|_sy6Y`23<#?txN@pSF(FA_Y#< zSB*?JO?OGSNLU#r{^w<_YV%Bv!$rrjtG)QxW>@5z2hEzqaQpxZyN6EZ0aaqPCh+=p z;2yn$@|2^`EqGf2cBOz+NzdTUYau&^rth6oxryK5n6-js?OmF*WwrP zTJI|`^~FV%_E{?TDr0GQwc?qqUtL5yp7U!0=Ei2u1~BE}n-i)j{rnR`>bD3bNa>&p z<0K{7znRXi{2b2yB1+Lht?`;6jC>+A0SpYqTUg^s9}3@AD!HXA^(yx8F*epjW;=|{QN*nj z1$nf5_v38Er9S(P^B?&yy$s1rS{Me?F--(4jmDQ;Np-qoerDa@9Qiyg+uB z*v(TkV8|QT;zcz-F;0_id}s-wqLQcR@f={;I*@;eOifml;y!*uNmFx-|7BADXEIG5 z-3HBEt_>_F&&k}Ea!3NLpky|_cVKp03?Sa;IuDcgDsYeMKQxbs^a2PY&}iwddkkHL$J9 z8_}1#Cfc^4AWVYCB#A`xz^$w-+Fvb;JZl=iO9kq;hp6Q*T5fj^1Il`OQS(ZvQoveI zWHh4-K~Z}U@esomxHj#i#|>FL_g|xR%WGw`=|ao3<>);D*Dr>X$$a2Uw!EXtk`T-`>SO_~yJ4^AVOJiss$DQ|ODTF{Gn1PRdd`K? ztx3t$DYfdFF&XcwHA6>Z+%3P+IFKb|UmpA&g??KPvg8wcu*W}FV^t&$DK)0p7~sAi zTl|eHc%`MD3n`PYL_w~k(MX?NgbgUET3Kx_qN;WuFBuGj(k*$nR4kEIN;L*WEr8K9 zAx^nUAc0zW_hi?Xj=;?PyC2))aqX2!bE2uPnKU&_o2 zfRTGgK@7qyP%MHy*xRjMaMGuDC}88y!aKHT3LU=yt!nx1d_}#*UOqZy?X=>V|1I0- zP?hb?bp8=peFjIT6Q1k2UFgY_u2ua$&zR^h3rzJ$$|}&*s)j2F3;d(O^oI%=QW-`C z>M-;m9!{#zEI6#d<`rmkpE`emM!%Uh_GKC><;HiTBlgG$9`I=_W9k#ax1IHmFaOa2 z^v4ny(k#eU{OthR^wyoe{|C*7ZD;x-t9} z8SUDgZB}m7LRGzmwZdKf*{AHPZB;JgtcjY&k`nN2x<`_N=19vF*U+0AwzWnyS$RJt zVt7Zdwf+`|NF|)djFB(oVDZCHHE-Z_iClHP+k4w~QfTGGl`r)M+xq}*SW$98Y#U}AsYmCL9ZEjrKr>gMP-R-H%y6l|zs(bm1^ z4#*WQe-OmClJyxoiyv7VU8~b3p#h+S?eH=P)*?35*vTcurlcW#@nJK ze3utMT-m|zwOv)+GukI#do8sJp}2e&f(|~yKZfm$rWMOX^OeMUl7eTVS-lTp!AR}kwf>HLf0cE9R9SqYthMHgRiJd)h6 zXi-)u3;oCLoV&Gc&0`|AcO54-J2C^|Se37gX6_PjsNJNm=iF&rJ3FwHTJn61gv3fiI++a6@G{HRiBP-8 z=`FP4a^SXAL1z0cX^M8g0f68BHj%;-9ZjNNm^U*S6<3XlKk}ugh{VQxjLRE`-}g5Q zRJAHkTo5XD3PwpEPF$D!WNlxljxtF(<4{bpL2J&_sW_R12u-5ARxd7D>e0j`$Cm}^ zYQUf@ZdvKz27{%FC<2TfFmE1gs*k;46#9v%?lZhgtz0!{&R;0s{TezNJgT8lu4Q)V zAX948uXfk_O_*t%t~I$5O4!8SN~uyYzN2nPrz7^2EzzRSe2wN{yPanhrOZ~^1ktt; zy`dp!z@j^1nBQ84EBSl^Y(FO4ekJ z-0xfZ8xR}6+V?P>zlzZBdmYD_c3oCr#GCS<3&+^s5W!9}GEJl(wcQ+&qy;!Oegf+E z5k;h?xsuga1Ub-=8*8jpFu5wvL8tSoX>F&Qz(tfdn}FMk~Cqa&V| zhePh`cG~@ibr1TLm#ulxqDV(OfgAd|W;-hTyn|Hs<7Zc#mF)x5G-y%EAG^Wb>k2~) zLcMDkviA5S5bb=$$G-_l4fN9ewMgwaYAoh}^n)Gn&f_>K6zz>fI__v=R=OdRbx&?E*l1DLPvQqe&!4wBJWT#9{x_h(;UFZXQAo_Jn8+76#+^sa{?5Yx; z+8V}s)4-SW5uE)*J*;8tIDLo(XIA*OtBc81_UPFZt;~rDX<>^(_m?$9pquW`DF_5k zoTo0PC}9JI&~pl7gFj|l`e2pz?z=^+QP5dbrx+P@1Qy!Oy_-n(cJaRKqKaawyghHV z3GIEIMXEoiYMoKuYS|CzD+eTq&O>|ht~G?@QsKfZ4s(tlj`k-#57K*+TFs1M#2dTC z*{8ruQi9g)Fn*)OznslIAr@Fz?EQ@a?gp1IiHnhN3=j=Tnlw4|`>kK9ilvfVcrIv2 zj;=-ey5>+=l2wOsmGikO{~dGkC0x|LusCs?n@39Sw7A$Q&e!>PR^_w4_ggqsu9e;T zrDI#TqD_kYnKo;%(ap@*sV&WwBZa@Z?J4=JRg@W>kQY(~XJ~}khwH9#*-j@By3j*R zj%R`s&F8%;Jfsx?V+n7+R^F#m`B}EMH?#2gYT~stF|@jq#F@#Bt5S<6=CF{PTJK=j z)G?yOCrD>U=Ta+4FQ<38)%4s;co|Wn!y`r$#|-Xlz}U7z(o6{(G{cA9bR-3<_*2j;I4NtE2v)ELkC!ZqL0)HNtUdvCd#L|(zI(f1fA~XmF zj-$Be4;wrdm26Xf){>E<`7fC7Feqf+)Q$if?-lH)%_~nquO{02@*^789%zhB1sfW_ z3cK{_-+-r)t*^q!EmXd+-#Wj)T36|9qPX9fuC{BvI6Jn8RspgrI2rT^w#cNLei3)o z!7uye+>(#f5fe=yQqRdRS%>I3>H(aw&R9JFwDt(MvbP;$bo0kV4=nKYuCervYsY7G z`=~LGZ1GugJhWAnBBhQY8t29$w1QMbr+DPDtETICiZ(z#WS%!_{#gF}LucKVjv?I- zABpE%^^<>?b8PLF)|oS9`&+-7Y+kql2AB{xIYhFd1#E`-5NP{ABE~sm38JC7&LHGX z2VYI1p&coed+XkzCvxWH7cRggpOrUEUwa-9|JFf^>I)4aRqzrqVA7(=lm3lX*D!54(dO-VMcQc`B8`YVaUKRrUK!D`F(Z$0;Eua)j6ZHSWDiRh zqyg0RtJ*r_(j7MX45{n;{z)1V!796&iFY=hSrjNGGga+FKNfsy=a3BplDtl zSk&14tm|Umd{WJ={pxdgSAcM2&w%gg9<~CL11CvG_B8RG0pKfk%S;Jw>SnZ<2}dkH zQv|k4FbS~UmEpwE@rLkozaP3(DMru1!G)viUt7U#^FtWSKhK@%uAll527=ynwIK>7 zY(tKJ@@wxE-bXHFJTF!Cv$wj&G$4b`(muwhsj`E=9D7=;0Q96eAgfW~J`DVwd!(|5 zy1+j&u!F+|gBjUjgeYhr#Uh7f)wYjuk=R4tQBKEKHWGlvy{=@Sk|<}_?H{JRu{DgR zk0rdkeLaX_=Ke-3-RIKYi>-uR45{Fn%7%4f)h3&2FDFZIA`?(nYA4GEs!i+CY{))g zSohCX8ml}GZCckJ=%R9*0F7rF-BxsDt1t<{h8NL45$2GPXa{`r8LvQ4aL|u3=|_N> z=cFVpA_7%470qdK4875$EvP0zvF;}c9jA&Bt+N>$8NWz|y+{3(NWBx?+;2c6Dq;8F$YC@cYCBp1DtP6>FI$0A3OOq3L) zPnm!Xbj%zlIJHVCa2l(V5Tvmf83^<(qX@l~^&CcdtiuYrMR05+V5UkO{jLY`N?gvS z12TIQTtX(ys3r~3P&uAA7yKJ(qTEF$N?NGZl254`Pl6@}(Ja*!`c#ZYlQ|+K$yt|{ zsB(-rXlY-5kOhFn6Mj-wpR2TW+CO)O0*MCUOq29tpbih4?1oiP z+!Q!%o-uE)37X7`{0QkaECQjQ)@T*TdO^YY2%({qDnrs5A!|e)ARBN*jb^SF)bJ9h zb4sF_I$h_=PhRAZ=)Krkpv0|CBhjE^vKf+|Vk|i9n(IC2!&|P0Yp^kgC+8l=cLrz| zt+QBp*Un1Em-_-Q$%Gd}z&xm-0S~J?HN$%InuoA^PNoa64<`uq`gW+Za*YjL)ME#? zxzinXIEpOveb@Mu{`eS4dPg_cd1UwRKmTU;Kyv^H002G|007tj(4lQ-Z{Xl!qGw=j zZD;hKGnA%P`)v=|5V|j@!Ny4$LCR$9WPd5AVrKc%v=bdy%L5V5GXhFJDk?Tw%=_KM zCmPwgEsDa^Vv#Tj!Qt zyf68jE_Wz%t3X`zfg6zE6j!LMjw8W|@mC?CZ|ge0#-9~eK1NyQ=FiDiT$ZfpRGPdL zfxj{b%nG*TyNR=e(9Jj6aUab=idg7Giho+iiQ#4=`-{0%#`9^GqftGYZD)^KPxJx| zJGF7A*{ zaq*Trl%PwU*ls$FDK8l|UbWjZsH;MP#j=?}P*+Mr3P}mZ0qfmphS)>JE2+UZE)rxT zy_V9Vf+%0f2^OrVkJQU1Qz3D*Lf;Dmw^okFuq3f!&p2pNtn^yQSXRoj6P%(n;G5%!Zsd$Xf2}paIS3XOQA;kul=nt=?mEe- z6?BBBP7Ia)U{9Y9zpnvyl=rYU+BT{OSP`7CNEa1^x}eb^j|Nz{KS>VxC7@=^H++VH zI2JmDv&Ix&Sl8IR#(&5`48fExY8;MYH*X;&Wcw#um5?gzl?Z<=GkA$^3_Q>{(D@>c z5A!dpFfmWCM?Dl;u!q`iJctvLDW!(SR5|dZX|z(V15gx626q9bBs&YqqFI7nWZ>h$o*30706CM*7M2KYeH8JrVr z;^CI+iYK_#D{dJep78zN!nBw37*4Zi>f~~b_M8*EPh{-5ZWXSwly3E!puc(`AB=JJ zH65$NNT$+uNOLR1dfcpU*hQC(gg+~;q?Vl*KWEFjp||2q$)P-yRtp{D{(KFHwg^6S zaVYy(ee?WTxnA7Y;!LU2@8CFzr0mHjv zKW0e`o&&{U?@88!XvDpb`I!`*nV{Od|h{lUst!MT@?R+K|G6vXM`9(u@t;8005l-!=d;8J%`b=ceHT*&oi$@<(J)o z7{X671;&#uKtXYLkMgv1jK+Y}Na>D?BacRGci(w5yBU44#q#$~MhhfKnw6tsRI+{- z^RD+U`{CX381&SqQ4zZqbdVtgzTd~6LkzN*@yUTp|0`^#I)dhsQ#I7KHZ-i|%9H#F z=visy3a!nv&hF*X&@MWIU8*_OX474iiS719mmQvg4VF$<82Am_ewORa%bHf^65R_T za(~97m_V=P%jTBK;P(+6=LmGyEUk|+gyPDnpjvi?^p2(ErHoJIl#wf_P?&TXX@34O#{l$rm4pPxty6&5N9bF=Ee8Olw( zVFEoIVf90YQ(3E(=YY}z{GUV$6~Q0ylWAI8&|cXIX{A**lH^1uFvRR}K@M~4nK8uf zJyFV_5s=Lcad1qvzv=|}z>(c3;*T$TXG?<2CutJR?t2Sr`XvCKi(ljKqe&(M5sthU zWio~cGmp%lm>t1*O98P+8CQF!Ax$dM5FAh6HpGA#r!&tt&0QkM69g(9$och1&U55= z96r?+UA_Vn^|$^Jc|3^a5m~)-oCys^A(j1@2*RgFe-XMm7ByhIULr94-QcxS>flS} zFqlx%52>+Mu~}#?7&P%HyB5e9?r(?@f;5_ahkhPL)cqDfkN=9vg} zEpwP)ESX408dpR})hntMUldoNv^vc}RB@z`T@8`UV}BC2?>ckqD-_CA=G`ceZxp}- zKj>+m&$9@D*a`QSH3~?qjIm(Lu|IT;nvTNX&BV^9I)iI`iP(5q$8jH*-1U+R(i`mS zF%gg%KjT5Wi z&Prz=Y5Q2km7=k5p-qm-y9*9o%bQO85xi?eNAVQ(Ra&kS4sKZ0Z`@Ja69h^J%?61m zuoE=zyjELJTG!+GP8YFzRZefj6TE0LE!(-~${#LN4flcby2w|Qu$SNb#drN86m1(V zO(+UG%+(Ce?fof}EsK+`d4xc%_zkNpNifNo%}7$LsE?13{)S#t*-K|LkKYvSWm61Y z0`vwki=eL3=uZ}ay;n-9YFW-^QeS2I-Xp9S=*iac@acZO*&Ydh`bm>zBOPIpO}Y(i z4~f{Iohot7;|_p}K$R|iVtdnmUxoGoK+#Q+*W#K3c~=^@8J{gQ*TsQ6D`{o^t1bJB zC*FN(rIuqW^*id96G#v}vTV~5@Z+W~phXwQ=xd}x+8quZ{Uu)iE$Pw;_LIml#M)u^ z=#EZj`~8=%6-0fw z3nrLnscSfkjtl-i^V=n)C6`O^y)^WqsOK9>=E#0InLgw|Kh@25gRjxFcAvB5YrWLG&upGc)hKJMf$*W!1m{?{R$dr`cBF6KV$M|&XDO;-tY^Vlok1B}D51G|+O>k=Y9sxF zL6iB!D1cc{nk?iPv(A}?AT(D(HYQx}L5U#T3x^XR&@`STu1DoJN zS3zBc4t=3F3zKT7EFX$HtWspXHAfoS)T!KNuGxoGHRW7CCGglfY8mq9uONZ3&ov9@ zB-IBA>uh0>-2J&NK7*Fc<7GqaN?M?hHqPY+1S@86q6B-)h1K_;1+k0Nw!2*h_30S6 zH8kD!f0^*EYU;6qhhZL8-VH@N?2V_iky3(c(=Qx_hOh+xK^lq{il<4X?97EsC;cU% z1V;jQXG5dNHZ2lJKLatEWac_Ze1~-QE-J+tMgq#FCjygX@SHpp`0E-tDu@DF!#l=} z78!vYh=|P$Xi(&Udu~7d#Th1%I(?BPeV;g^F+8G#*l}3Ix}g>!x-YOe5L81%QQi0t z(LPE&4ZSf>I7HT>ec)L*#AE0P&}+2Fe3Xjj^{i#KB8g-vA}_(Pv`prLz?x&ODj-$Z z2NC{jAlMY$nOEd+yz?J;PEMaR0|Z+kiIbyDN4rN@$$E0Z)P?rrXs%o92~gyWeES@d z0_4oa$57B@J14dQfs73Whm625y1I-B~~*vZxL1fzk~>fv5agF2gq zbEm5t_V&aH>3BR)|HjGG;^^#%p|Jg@g7;o3(=iwsXjG@2Qj?>VUbCf1*!FS@bvUgI6X7~;bkuemD3>lk>< zDbGT;w*6b%q(}HnJcCo`+{0lhAoOSyd|g5vCo<+L7SmGdTbZ#H)eEzWE<>RjRRXBjqkZy?XASdwqYaet+5FcmWJd zBd7HIIoi_+1^zN)*^PVLPQn`7-uqVWZs)m+xY%r+nw!u>J27JtmLisV{Wg7dGkwMW z_w(J*?!Zs>XMA2k{Lhn*|EW>1_hZU-EVQ98Z+^_e8ae875 zHL{szr9d0YClrL{PI1YkZBDRDjR{XpQ=_@)liI8{HP1R#(V@zxbF4_op(D;NWZN^k zf13FO4bCeu`=c!3^(|jmbS_lL)Iuf{p&0_3Q|*&oN;Xta?5n4nCLHGR7SQ}i0+UNT ze!U?w6*-yYV4W(DKcmCnG6%mDV=)Ye$eKFxth3Ud%$1HU2$gz0Sj(E>;z0Pb)l3{g z$d`jj4K*>WGP-;PAb?FzD62H$`3Zpl>smMv21=gbCcgW%3FIAPQnG8PNp6>>Im*@} zfnBjGTTol2q)um@*D9mEa>YnH7AVimZn$VlPL9{=jSu!GbK=dF_898NbtF<;{*)(- zvbqF;$knI)_G7>XRy=K^wy7d0m}o}wEZI0ogt;GP3kI6*W{aWRK;MKtJqbLaVBXX@ ztF)e7{$1z1Yan~rcsG>z^O{SWCq5mhcGaQTfSD`k586;-Abw3NqZSP)O_9Es5gbYO zzAc3zo2*DMHt@i_lRhjSWUD}Ltybov?>krSB^wpDCDM71PMdL9T#s0&gZu^iyy zy=nA2paC@(wvlr*gtM?Pptoe;UY3UD^^N1d<|W`2aflX3Oa;9)mmM{Jim-1##B1i; z&%9KN9FKSB<}z}8(+UimgJ5nXf}ZH!^os|vIv{7%(U>U*mM_(2NPvKfqR8Yd;EZ9P zD*M=hCc0jd;=nZk5!BWX7N~gb){#e^$u_4!VTny@(f{Qh_Rq;amXLojrNRtlQ>j`& zv7@O_6@csq0xuo;-hjG9DOwGJgZeQ1#26h06j_BsSRCa~YyR_yIEH2d`0x?VYPgNJ z@2wsl#E6W}MC%8?(qq2R;c`2sfUtoxZ8Au|dt+G5uD8o)8-Lx?ysTl%bz!TVX`|I^ zCg```xp}v5&~{^QDQfzzJ&_F(erT32>>Lz)0<9lPNHDXDPdo;{;Fx7P1;xNm1KJtH z3b!*oSzO`-cjp^V1K^9Lm3NSr|KB>=6>Lkr-ugc`}22WXX96%WiZDCF%9>x!>_v?<#V#uR9iEoF{6u+ zc$4=Hd(F5`7i>_1wE3`6^>*GM-r1Pnri1{$18?+DLoET#bCqo7xzWPZ1t?y)S;_MI z2x=95#iNgT(Ds7AaJB>C+U*vOp9f;3U;f!e67iJ3=@Yx1cphGox3J;*q!KQi{6;8R z+>K(QDe<+2&l~wvJ^uEjb^8t;zx4svqVxMNhLpQd^ZSvXHt4M%-QmC6?fc*Fg3eLw zkIiC0=zc&YHi5S{e+65ZgQ6@(G@!m3XEKFY!OCipWwTiJtIH`ynUhMP(nvjx*?oAJ zswS9C!eyW`V1U@=$9JlSDn~fS_03o9Q}zoHvyh0yp)fLssRI#WWr4M9f>Txaz2&c^ zs39P!^E>n$ij~b70gZ*fWrcLNKuB!VEIIff-Xpg`8=@>I4UhFkL6fSBuEy#>r0pn` z+G0R{(>c%DmGUk(0zD$IPYhXUO8`$OYi>4Aht+jgS#oU7qODtO>xA> z1oXS#DeDhT2K)XA=cdiguq0fVk#iNSZanM?yU9`oCvQK?YwK}BBSoQ=BWree``2HP zv=JBiU=u}e*~!C8Op4qWlhm?$**KHm@)MVvcvN&n04ARaeq|#=3Pna%#;P9D2m_wD zyJ}U@E+#jiW{+${4Nd&oTe=x*&h|>LYqNu2OA$t&Pv4}QC8GfPY^Ya2Z7p74J0_BK ze?4+BPE8`{;@8`znS3Se`j#Gw1Q^rMT!b-4zC6861yMf0{(aNYLFMFI{A{|2pH0X5 zKjdtFGXC|99siHpZr=7>48i9`EjkfhfMV;UXS-Z6rW=wPGt1M)@s|pr5&d}OZ}h8; zaoMV$#-Nq>cnX!gND!LNpJm6{glCFOKNp5xgonrdb04&Q-7h|&oQR>TRAB3O&x1q$ zQuFZD35sgcFHSj;R8`AOn~++cDc9Mh+!mTwozsG>1g-K?l4@;IvN6!ruah+@yRGgJ zpBwSH=y|}>spzJH21*zDhoQDmULA+}VW=yh(6^1|_rpZuJ62{Zef$+$Qwm8g60z2O z9su-^-Q_0&ck1LIup5 zB4PsZl=``zr9i0SyCXnvXNv}Mc!R%1GvLCE=vFx($2Ms@B z>wHlHYttvKdhd}-+UBqiJ=K*DJR8T} z*HfoR20}u4drWokv+FAG&9WmXZ#ly6<44_ItB)~;fSdY~!QXwjSuPRKLk9VO%qP|2%B==(Qz#YYj`|4j^0Q^%zS(rV%W zZn!NvQ%V{7%o*VnPW<9A6fSWO%BO^8N__YYHOF~`E-P5A-e=L@!;ErRmh}fwsb0?s zWM+7n*)!nZn+V|s$nfR(1} zT8zo*kOS%k<=1v9^!bq;p?$mlA!{6(-zT!Bx};m|sN2Ji7vg?j=wH;mvdN@vhPXv+ zR;J`-yEl!4_^wxF=AJ-y8!X>gdiOAdhGtF%xB!^c*iUKqQz*;x12pX`q}$3+GS3zr zD0_9%!n@f0xf;jk@Y8IApxdLrLCW)O8TDkwDHJsc8(+W<$`7xZbG6ZPiKXc9a zhl~EdoooM*`&d?ywfmR$rY57LZvZZ|K-LQ86>l;^MkQS}a{_3U+@p2;H6yhJy{4?@;`|}+r zu6k5QsTR+vY3VklMsM2*#ZG z-U0BJ-Qpwzw(#Xss)Xcr|EUkF6-Z_?aVWd4v6u~#2AZpsOC1o0x5yvyW}9~S8Eqg4 zXtWnXY(jZHfIp+{-~a$5tJ)Lf#izb+?wC)hWTFSrMh$1gB{oUHe02^bXRfh)8u`Lj zneEO2JM6@eP$#>kRg{>9%{AdTXS1<)tM4Vk8L!5GVe{|X#3Oq8!o0yB~BGzBAlV z!X#R$$FpP~&gu&hPpH9-u^uTub4VXA;A;U^yX?Z6Ym`66Y0?F-6Qt;2>GaT%&1CPGFpgWV#RtYitEvnbMwg z6$`igUzEL5tY}fUrMtA3ZQHhO+qP}nwr$(CZS7^-#@&CVQpri>=G2)FBlBsD%%|38 zAH98z{omai@@1C1#v2E`TxJ=C(^nJS zD`VaB6Kk)B#`_L|)^@s85sKNGD6gZIO>6t_?u)lkL@*&E))Nyc4XJHYj-ReuJy-dz z10%WzAT*=*#;^@my^$y>yWJcfpOqG6PxfPXj~it#|In=G7zeJBK9-|ey}A%znzLTz zQJ(6c(*i(PkiGH8n6n4ix+sNR%nl2O3e7mB`rFZ+JlB0%RDonB+`H&wY-nAAo{mP) zv{QleU4%cfl)I6GwLUbwzNWmiDTgy^e1Tq^Vno029$+jtr>{3*nsM1K-03TYm0+VwoZBQ0wbEPd&DAfPSeHdpeKuV^=H3!;QUMs0MOe1Kksw=tN#8w_qvtS7JK6EGZlSD zq}ao_YhqVNXCzriBFUy{47G)9@s+#T_ikMmVEmp`p`n>uBbwSs z!ksxY=C@!GU>-JW=fDT=(@9i1OBv0}#mJPJjVmf>EEkOG^m_0>W|Qv~E9Vr+|F*Ad z-Qcoe65V(zV0*G7&OIfpLawWp$}UJq(&%qLfSS=DFy~Kn1(a7o7|coj9N$BBS80&-kl); z36f2VZ9CX^_(MpaFA5a`F1`2{z)=qrjntHapku(f>A?4@{FpN!1w5bEn2PMA;FP*3 z`J!1FTsPU0enEMh71}k@7-(3t0XkNXz(A(+U1tT-O^|wX+zx&T&2_6m{rfEaIbLbk?OlJb; z`rM3jq=y8^+?VR}j~J@VoI!BYZ_l2_>Zn+;=^ieB*#Ob`@mxTSmg+aBv7JAYayi-o zG_s;M^w~{)9w)Jdn(pgmf+lTanz68Qo2ZPIdxGn7n40Wj|Jm11Pu%^Da)$JAT>oOk z%-j_3Vl-S%oOzmKK$otZWvI68GSo%yFhs)=F&^eHpfg=IF5RZhB09`X-%kS&bD8-F zMKiwv@QaDMMK4M4xdb@+>-Ei4TNPOyfE}sn&Ftu5%JT{a zB9?H913{6m;#|(?bK~!+XAxncqxn1zqC3M>;}9mlmYOu{*GNNQr5mol;-EVTDvh!L zRS%0TS(3-vEJ-pxX1jRaN(*bThPJdxPml>W-joo(Ivm~=FTBCc<SMhW|`w zJS445YAn)uVN9RqOT?nhwX#jK=GV3FUWz7LCcry;d(FW@kgh@7@@x8>~Zkw7hWj)-lm2F$XFVtJl zcW`tcuN484e>PVOwhfcJx_~6U(n%vx0+@-Q!rQIum@>;ZWTUb){+&RF`5f)P(Z&3m zckOWKrrb~oZ@jEb@U3TD(sj2_iziAFr7uqASE6;ADFY)u3f)li#>9w>ZtuV<9Mc*hT z+d`4gz$N@L{z4F{Fq8CRHe`UeNtX@IPN}Y#=JvP1B=0%wZ(f~9P5H#@J>lmqH?(#0 zc-i}8@n|p9V4N(vwRamh;UGo3?A3aJ9aJ(D6ClyeBSpJa8TB_{>sN$}3d~H52h$z< zO#(2UWVoh)yLQt)z_KsOb5!xHVR>hRP@#u1v8OTcuf^YfcA4@aWapU}rf>70osBys zmYRqs`Eunq?nZ;*n|_RgLeFFGqc=Vl{A1C#>`vaQE~9H;&sU`f)N9hYm` zH$eLDriu3shQ@_?^uE~V+%il}S>n+sz68*GR_U`8@gnbp%Ccg~+&eI3m`gBz4A!kT zrA3Loz7arL#*2coFAfXgvqjkro4pR{3}7^LZCYt2HY-D|3AP%gl`Kq+!&!Gj0jNKr zM~Es_Jf{v#_`@}1W!n-(*a+x5y&*0jimXVWyxJUoP=l;XklcOpdo`?8sqol=p^R{; zqJl>HDG|qnx3}1y)B_^ELVAH3NEezEe5B$86RZjGnD-c+#G&ZfuUunMHh0fNX0urz z$idXiS~ji#^>Jw1fMUHhaBH^poP5FapZjNK@KI1k)vgLdhnTFjicPXir@ zk=+rhr3q3h>d%^l*5cCNd`h$iOClP+ZAp&agO=TPW| zCGnE0Eo{^qeFa2PzlTmN)+VQfi$oc?J&0D(hPy^ z!H4A%JibE~Na*E7zbq&@MngRsb+|z$ez+4gTOMiVZyV+*OkS~DyUF&Sw~oSwHe`|R z=xGfv71pGx>W#!crI}zcR4L2gzQ(9%tg4&%=FeNBP#mN9g+{5AH#Gl7ae=0^N(2Ao zrEGku?AfMb(~r7}*)6p2dQw5Qk+YzwK8DBh|QQW zjcGylF(?uiG4WdQzRKo$*?j!3oe?^Qs6wk|*ARcuBKk&cQ^rFyK-5Ku*UZB&8> zPHVa}ni68Tbt`O6a&c|N0dxLxo zGPF~+fFqARusl?5RSzMMRt^t`YjH2fz@kB0!H5*hp^AAIA9FuWc^B{n&OAuVmfhjc z+ofgiz|QeFC~gU6POUx`VyXl-r}51XAZH+pgBRd0ZqJDol;YGQ{#2-rmSMDj2`nrF zC;obn>~TdFNr>BnqNz1Joc=llH>sx39EO*l!U&-lDonOD0^AV~6e@$Wnb*@tx+(b- zmV$WiD^kaHl~1d6M4<4c!ZECt1JzWe$z9&^i5;s1KUNe`V4-rbx9m6tZWhYZ0HKkV zWkUZQ9$a5W0H!-YPAPBvms`B&R$s$;#nDtzay`~xf2aMVa5$&egQ4DQ)Wd8Mj4QK> z=hlt(YQSErmdm;n85JjXF(YjH>YRGzozcq*ZvL-r2YkW?`u^ zpGsey-Xn&&%D<_&(la*ZUW2B*gHuVWuUhq%U8?69tG$-TS&MIr2;^!Ge2$+8{jP-S z!>6=YA|;6IG~iyM04$GE9N@`x=#AzG)~U6odK5Kqe~n!PBRaGYJf>!!h}6yP6*wN5 ze^m=fWjQR+(lm8)oH^dzYz-XO5x!<%>IGF1@O>U>)ddeWGlNq;sOXrF)Bg$-8}mc% zd7trbtjH#z&C;}EVYBu6@+hg!OFh9)p?+OD zd&yqq(X%ZKS!~2w>_kBX)6TF?SUv$~!i=Ra0#pJuFbnR2pU#2@i9UM&w4LD*qPE6k zvPj)sesz78sbJboeqAf?jv`bi39?8;?$2_{3#%^!)|uI!v2=m!^m&H%uNkuEGO`|yatdmSocbI;$i4oTq+t5QSc7apzhLY z!RjGT^3?55(fM;?r8+8r&XM2FD0%3v+5b~fW3IHi^tNmY{U8XCOWxKj9i?(B@ zVIvV>^x$$ItE<20p_WY3cm@4q#!{EYzpsz2vDRs ztq9y+-^H|{+gUIsHUkCT0NY_r$RNT}@P^JD-J}}i+u14v)EEJ@7p;Pdl3|tsVi_0$ zQEu_HJx1bt0{@xc;)7QdS|^g0k`9mA+db~pleK;+q5Tg4i7W4-2#!sMv>raU3*nBe zj#f8XP&UBqIwFmSNHL`+5AB zHSxhLZI@uSUf&m;YY39pjBZ1p`6^VYlfeGRUAhaKK{&K54}VZo>zUA`c6?ZPQP|_< zjKAiZWScBvW84`4oqe}PjLYA2g=dV^rQfSX$|5@zDrA>k2hWVUOI<*9oCp}MI z!le@H5@Al;Y!9+E>XK!+$2MNC2()GAHOtpaO_;D_Nw6l8nJ^1nVC6$x>)l_8LU9G* zL~vUI?eu*VmK|1K=}!_KT<4fNg89cn3kX=PqHGg(TOmXG^Vi3L{l$+k9S%3JA{7v)56PbY1g%z{K3WGNxx z@n(h#8|?0cHM~Ys7!`DJKK*2W7JIF<08rniUDFBrX?yOtWpz=Om9_H8$2i^TR5@2)WddF zL0y8|E_@_fbn9)Myc2UvLk)@%#Fd=8B3T8?W$&mH+D@lUP4SPW&(@kF=gAWm9Fv%F zL*Qo!CdMrlK-ve8S<8ui$hHth1r_rcj7~4R zv6-2j($Bf`yv_>X$m$1BEbo>$OB=7&P1>#b0zxFzlqwo@q5`1zkEtgTMaW*14V__@ z(olO)LTOMJVor1u-ziyq953(Y?k0M$HTS33z-Pg8JRt!EO!>T=U_eFIPt^xFv5qpT z%4316D#u&POyZj*>y2nT2;=X0ODYn9ygl^Bd2nKCISny$s5rH=eT?Lks0L63r<96!3f65(bDQHUZrqm15LM*Uq$|$POV1qKYA-H{IH)e+`iE zBlnD!aq|T7xu;vYH!iA+k3XQ%mXNzw$G|OQqPKnYtDJ z8qC`0X|R4m#Dxm$!?&n8-Z2j)AxXM9k}GH*HV|+0GLJ|XMd5|lt`O69W#;Xv-9;Z4bm)6pl|dr>d6S? zEGFy6Aw#lNrY~u%=fxTSzNO<_y08)dI zl53x~U3c12-fp$~N{smo;NNR_4xtzjTFRV*8X<&lWwXaf#5jFkKsN~L0!n;)*QD< zUue@a1?PXsVC<5K4v8ShFv|TWSYVjL*li8{Bue%LLf-Eyc~#vR zniHfOTiNH}Jj^g|=zD8*Gm~qf0_{WUJl2;F zF@QQ9W!8jswU;)pB_YQfe(?yX0My9Th#HMu%b>_>CD8f^_tpCIrwZ4*G^Oibo{NUX z{4@^pNO%}=&a>{gX?sX@XdULf-C}3@(%2m8~)LKaGEwci0UQ)I5a2+WN>axBHAoP8=v)u)nA}5JI zvOWOnlOBLup}#yn79}&g3c|JodqGh5W~||7kKYpInl56(C|6F!vQWSXbXZDu5akuaKkZdGd7CBr zymhQs`aa$z)+=rx4SfNBCXz`dou*5n$f%1QP%U4Cm{dU1BHr4CpjJxIBn*zeK1onx9M=k0W9e&Oq~s z292mrl@g1|u+;jBRMz4a*(ruVG1UTYXy`JmUP(9&npz zEkBHE$mxtS34HwIFtH9J^;*|5Ll_u9zO)-~3nL2B%v@c+vXmRVCFnn3cuz2p`Dk7N z_h{A_Wg!6XC=#o_aEbSh@#x> zpzbn@O}`BJd`k6eD88`xr54i%iUIFV%P5I#J-($(-st5_r4}>v!7`f~OEj5E&SYG` zSEI|*m&Mf^ZQRZyjW6L>BoEqEeqhOv{-OfG^vi}D$tfGlTAJh8LN1{3-9 zZyeLm*jNn4*6qaDic6ktu?YE5zEbZJILP-VbP0kf$;(XO=tbE&9^Oe8& z$2w%Fn9NT+M4)DlK3u9=5A)qxsl29I%)0AraXY5MH_ZyTsxo#1IG4M5YIT#~jFooz zz`+XDD&qPp>4#HGkZd;(=;KOK+dI;28N> z-UY`Eh2hF+U3kw&7p37s!+U+?I@<9?l;g8V$48;IkNC0VOe_lEk4C(Hkt2#*HiE!l z;gEQQi@u6sTS-H-=s@ZPWi+d;?K2LEq=LEJPRF(eWzVsl*RMP{!&!F@9lUL{K9Q*j z0P<3Q!2K!*{f|3#x$-T63d&nD`4K0@58z(H_A|qiV#sdex>VOC7Ro3l@9Zp{T`dmm z8%D`ni=>e#1#Wi`ULS?+Ih)F7QvOTSzx3gr_W&eCh8ia$MJ?XRd(FS`yQm%RKaQIX zi_+nxkIGC0o9+D_tSkg)VpD3UFO5&_5bHJ^=@x3pk)`@y^ANJ)`gmn%@%XiV*ZC0o z?_;6d%``5sHLIYqVv5Bs4xW@N-#O0rxC~IyV{cPSr=qu;>oo|@a8gQm(C;3@5AcmY zlS0~(_!|g1)24=uw|EeVd{UZge~-u{CD{2=;K$qF(Lxeoc6MDhaKRh`U$Nvx+}`jQojKqMb=kSZ{&M zQ|i26_Nv3=mQ{4Bi`%|Dy~|*E8{1j7Q?p8KC$VP%%dkSg zp&(8q6^3a5mDs+?NAJ>VtB|MM+PT)rw@IW0viD>6e;ze~O`jThr>pXTgv%S0m1*}x z&XL&LgN;y~6kna`Hn;>Ap&sqONZf1ZTCt3CvfAws7Mf%xL-sMPzRf&mmdo_Mo|`it z&M;>>SjCLeEDH`;sCktdTXe%zS&GoH%|`|&llpL<2J_FOt!Ar@)9fZ8&sr^FjvHp3vPahVH3oI;-Cl49P)qy~$ zoa6FWw0OF>9KtTPoQ2~sm|{~k;CcrmzFGUCf=_1^8s@c! z!m4GAtBxWyTyN(Dg_@ zBh@8fnsSf&R@39pw;6gYeYeT57uH;Ve+ftRiJ5Q>KMtK^e2U3vj4C%N>~^#iZLNpr zL#6?w%`wn)2i8B@gNC5~yUWm2dJ$yERLG7+WZ6=Ff7@pxwF`@F(%+`+%kg0?!snhl zVaC6evV1)<`+#de?q}xgC>Yd(e=^NCGMLLg$w$x!K$H2ur>1jB=JwFIC)qeQSNhLILq@y=nKPc zyaYFPLM&>kg*(he*g&{3Jr^_)-TMgs9j_%L7%~^2I&`*vlGS9skVu~O)HnHq1hj6Z z!;Df}Dp8?P)<5zv0MZ#GY3G@-5$?Ff9}^x^@8HO}8O6MK86^_ZfH{>zRKv<4Y$&@; zDia1HPsiTCHQ|SkzMc0b6V563fmdTIhG>%w8C`6DgA=pTTIK_a%~K*2z&QKuO7W{u z!1BxCwb0k^UpQ6ubG~799vpH zB`suc*l#8Wr^&9sS}1dnAbc3LajE@Em_~J_!kbLUR@CB6He$lq^ioM`t^(czBwzBk+Q+X?ptyA2Od?azYQ_aqrTblk(kg|F8ZA|TkwjS;KpUqFu29UZXhiqB=Nxb%9TQKU+0&Q7+{U`I9C zfr8@)NNrfcZlO=+xHQdTUIKh;)JD$u%`nXRsx9Fdfz&z_SPL=3V~Re9L3uAqNpT5n ze@~7oI)P2hto$Jt&-?3~=;o9g*oo-4dfYUURWCyvbT;(0o~PQt08V0{cYi0txp!)QDadz(;>1^gR%yhS%$~s4!^1RlQr1kFFaZijhx|La| z6`ncuA{AM2|K<@7tVg~90xAXCEGu{8Fc4|N;}NB{W|+*f|Ejkk*ObEipFAa60L@^9 zHvuYM48{FPK;xgW6GYYBOo`G4)!dE0YuL>rU4X~om^1BAQKPm@8~4gT2p*eR`_Hi3 zYeeI0#?y*wtoF8f($M*@x16u4DNLUBV8Z8GrJUEOC97C750Yeul>{ESl!n6k$f~k& zSO$v~OrG`6VEWDl0EoSoc*J{@j|}PilDu@&qQ@pm)-KkF0U*X>rZwqCSHj+Wi|O96 zw|09HK9{3F@P0=AKXLkvo8HxK; z!9MJ*oW43Y9yA-~U`EBJt(s(FS+{iNyTp-}YF2IOmy6dZ3+AV~7|-k*!p^@hm~1#C zyko|gKd*1}3jAi)uaV_r5rVS8p?b?69m)Oe5&i7}08FQ0AnQ{kAbZovlyJ9(BUrLw zF;Vyeq$zt;@?4mOQ<@gY0jfiU)YBr=)U$k{niWg-2*qLN$Yd@ewR-NpF(oe0jb>&q zm1{?t4Xby1kLHU_XJG=6?fNC|5JoY9TzNB>5neiKG?SW^=_S3QaIjAeA-6+sV|74< zmwA6_83^EMs%-NLP0n%HxH<(iP!Tv{=4`JOvt#4-z{R`P)Y!<@(A1n4ic$1L7XYZG zBv*Gfo(MP^>FN1R@Ql&8b2oKX9y_x0OH{gjvSjHN)i{CTVeWqa>wML71+U%*7yv*J z(*Hal#Mscx+Rp61v689V*llVe{@my>SQbMnO4@qe-h`QWwZO6uQ|hm>S`@Vkf_?IL zuhEUuSv0Bqe)2lS!ng`8e_N5ytFlc9tj%18uRlzW!h+rO~wBDdmrMQ+)_#pRViFrV!r4S zAZ^S(M}bf>O@x3ZwyaXA?!XmI+8z>}jGb3Tm~e%}hnHQ}MGZR;Z|X4xY^p*LAukaw za5?h;1j{`y>iCVH8EuRiNZFyhC!d&-$gF6x00Qi%5ZXM_F#4Z#MYGz_&i3;4DgP>{ zLWDK#S(lUxNGeE_n0>u1T#wn5-&tpx!N)}x+p7qcf+?+sIvPx_DXq0!-G5-zY0}io zgpPFo&O4n?$73#hZYCaa-b3Ia?d`;8-*e4eu~?}WZ;qw{=uI7`{jF3sd@qLF8qycT z$gb80i~Tp|rqfn9)?EzpqLy?AWTMl^lT@zWQNI}}FVoMq$poq`z4{s|bS4Xn&R!nf z8R@iCDz|fYR03)vL$AXOi@BN!_*H|1YAmb$BsZH`Q?erCT`mS)P5Z^}Y>myu15`;J zt1Bn=u`-7EAipL+4=F3_$DrpOLHbfJu5uU8)jl=-K?0fS4vrS?qE{sG_@w*EmXj+c z`#aUNT)R)I-NK4PY2^9b5#0H&uiG^Z-~v2p zF)R*d&R$itplf+w)Tg?&nmzyfU?WhiEFZJM6UmTijzG1Kg_r13LomuDW4#29j)slv zOpK1#t4>*D9w^{jB*9aJY0Tam;*?gSB>Pt0c#O_xXH8BXPE+c#BfIDRavHrf81coCxKl7ym!?hd3jrWzU; z4PDCp9cD36+4``Dv6@P2-|%y;4b&ZXyIuIPJhoFN>Y3mvH&R)zAKHO2!# zM}p$0J@zJ3wj}Z=QqY&pg->>Csrav%f_NCWiUpODw=!8#NUfSS-=?4yj|F^fwK1)R(kKZt{k`?B=VSs7*=12#&?Lqw&?NQs~MhRN!g z(n_`EkDgaTRB&V$bzPI-1s0OD0V6)gHjIQFm<`19q>|rqa_tPg55Hz4mFGI@Vw-~B z6H^?!PYWkZx?Ni*ZBLO|kmhSoIMoK($HzUGS~11>?cb56rlNzNaNbtRX3Wa<9djWf z7w1mhWPKe_Cg?xLpfBX|S_g zti_kKt?P5byRCQXwz4+swK&Cq)!n^3QLcVlI0Fhxx#@d@zJ+ez3#99DVJ||Q@=48F zuUp_g!6x`rc)Isiu zg|!pi|3OI_AKojwxI+N|f}H*HiT0g?ez5V|=Mf3kYrA5`|KkTNT-af-jU-tG#1jimp8*xgE!{8JEr7hwZ z*|H@=y86m%5vwd_wdX!JQyWC^l*-o167s2=Zl1aBtK7ctHM}74x=Jwv;$lZKrk)fE z>b(9Qrvl&`+5Vb^XVfRi%9vo00@ualO3y+Zxh!S65MZEVer0(wOhui4&1mRSK@|K8 z%OaRyLlR@qrOtUh0>lhTVF;Y0wCjf!+inGt>M(DNbF&V6m53%6A91dqTJ(OztKWYa$;>8@(5XlYFa7~c?H{v zT=feaoEB{c0CMM$42L`P$J7Fb#`}XAK~C5|Jfs=&9n3s0`^+HDF8l+$Aj7Gv=&Qf* zf0*~ir7M#-(?m#K-Z{iBSa31NMMz>0HQoiAW?(dUK<15hpZyo<6sc1sQ;x1gGOCM^ zZEB0lEvsQA=~4o0I)g;>{i!{f`(}ohr~nAxTjt|3q}LLobr}=ea+d8?2x^I|lsx7& z#bo48%G=lcwjR_w@x17hCK&|`L&lHw%8@^g*HM!OLHn7RugsM+rNK=oAQ(@CgQyj` z#?!l7z8i5N$yPtV6 zh4Mf;$R$%6N=jWSPos`043nUFg5-&((Q| z>`E0~5#z1}n#yRmz4+JY_b1h^_t9?aCyc7Zfmb5ocUbpDwMd%T=U-N01k{ECJj&9`hqKn?05F|_jrj$bE%@W<~Jwo}!gw}mj{=_7OchPPr4%QC0Av=&lS11Q=_xCNpJA$*S(@af`UA1W-;pRlyjVOz3ZX^zm z@2BOVsg;uDT+1aNFOT-a=QPasm&uv;<+E%vI2C;M{C?ivrU_WalUgS)4{31_XI*O= zlC8Z~uLO&N-KiQUOE;?XI4fC`f2}TsHB1uqIsmbdL!rM%2t`=Df#(rIP0fB3%3EhI z>4geKziv(FjMcpOl1-bf0XuPnSqKiJ+b(f6@T!*=x6NbYkON^)VSWH!?&TY3*9KV@ z3|4b7=49KcOwT_35A#+pblIaC>%D@!bEnv!q;Q%Zx!B19TFDmLJ5kadMvZElNKLG9 zg0e=;)v6TcgbzuGkVhwUDS^2+H~lyRV#)x%6T%YtxNFuCK#B-$Ap*R(I9?WBzP6E# z<})_0Us38l{WXk`xop@B`%Uz&ITzD=2_yJCyXe+9zC|wDkF*;fzXj{>0oV$Pkyvq2 z--v=8#$DX=OV{>6Nt49MbNTrJ3vZ7NUI(pFiCVE+)WjS0VmpQ-P@t;_-drl5Eki$` z|0-yifSaVK{{)Tx9}bJ|zZEni*Z-lWZLz}t%<4Hz@ebRnY)LTb$0PwpP7i}vPbD1{ z56FWw3y*CRFT@*{ozMUFa!tw}8S}TnBEbif-d=m$gk1H$-^2-+qpk!|BNJN|DK;rW zOydpoxEB1m5gk-9Sf!$eDo=$p?bs3-*LrB#&mDahSm?nQiIOI~GNFo(&lS5YNA7u|v5v!t0 z$?x*)p;De0dkVfE(DQkV_c(pgF#kFQsp)_f>m_!ZqgMR|#ktM=$11iyxpKX{ct|}T zQAaf-w~optz6KkRkeIlZ`I1o8)hrenC9a-+JPjDGQxiy0@^_}wFhk-=a4Zoz->TTE zBvM)prLlo>T9mB4JoP`aW}rwce)@pe4S&ye6(cW4xOe)aeqCwyv z=_vJbv~7K6K7|78zpb2(0T#z#M}bL%HMc`u{4GCklr5Q4Q8*N<7v^7!iF_rBQztUICO+bP~NFa*S?Q6V_h>|MHX5?aj)=)C?3EB|2Wul)|y8wPP9?h* zVcEQ@yY!FRcJpc1%AI;60Y)mRMJi66mhpj=vdxXRWw^KwkRF z^C2j+} zy=YTFx;BSBLzMo37(Jp9LV@}b7d*_nYz$9TfFFbruDj6Jxo&tuxNS|J6oSn78VRS9 z!3Ai-ohcEU|2cK~2f;sCgAqQ9(PlUag7p-O>#ut!4zxdu6-6EXGlsq$g-{1W5FP;D zj;7E&M+N6l^qBy>pX?Qg`bG3l)%I2i+H?6J-s_l<2Zhkvjb0Yx8ZCj$Q|@MT=q=I9r*D7i5hadumJj>!Kh5bGrEVM z@&E+VFH7Rux8XzQi=-4Rga_7A!C+#1%QiOJk8F+cWT)s#-N^XsiJx%#_ zEdyyA@>UalipNl`POhs@yZ4XFM!Ys)fZ65&z!KvZDI>dkPb%6f;+4nIRRMx26kWCr z9gTD5o+!4QV?eE~0@EyS5(n}k&Af)3vvUi6D!3HEsv{c!zjDDBjW#TDY)|$C3u$ZP z&Q>GgK}l4`p+?<#a);Y3Z0-AE-(`MRhlrpQAgSYT%GO17SE80|*BZbYC9^BaQJ zzeFhnXlg>(hFa2}lJ0G%HP@=$96UHiD_hvNEBw@I>Pg@Rb^O*jzx6D^A{=9R*Ja)6 zE-J|7vr&WVYDf^*8RpBMT}7UkR!rR7RLs2s<V?Hcaa{Ak?bWsf8fr~x%WJJO$2u6XxCnat;UL4{CFDp6_jBv90$9aRF; zRF2zdoH!n-P6GF6e9HV-3es4V(8k>PFoeOQ%9<9bv8RHJuv25?fz7d-Jh~_OVuFw+ zw9D(SN4lb>W~c)p;eJWI4GI`x0aTfk!dVnMO7Qi8Lq>RV8kzmR0N2NyAF~i`UZOqg zT=@;#+4sbG*amSVTaVRuG3ya%V8UISiKP3=%H0lG@zX2%8Tx0YBPijyIX1X4{WBIy< z3fA@c%No8XIR!MZ=KgWJA(w;BmaWu|X-%DI@wp zDQ*G#qPxp*z_@?c)Om#o(;+~4meh4k6lYaH`@YOk!X+(jNO*=E?B{&hjuATjY!&o^ zBOy?udP3OiNm8>+P^1YE0mkB+h?11wLDWbCbw)G95gq*h3{dyqg-i>d^Fw+e>4Pzk z4Dxb_$jWyj^OF5}3CX5}C=<#i6V0q-TG+OlA~3T*-#KrUK!>{?s99m@a(1Xg{GP%3 zJMfjoR{Yxa*0VOP7utHx&RjpyiSa@`ZrD`wsx#%BY5W|sQ*QNKm+8#lSixssVfI&@ zc6eJLY1^u4yVRz2VK32EdaHf3?;~WTY1^yhcG2;(`Vw){8S|pm3Zp33cFEot4lGup zUh`5jc44Uot7$9H)tvZo^{VSg`?4q3@nA3*=0jv|I$%$Dtx;yk#EOjw*jLD>PGWYR znHo2}FTGx+?KbPGmf?)+WLFG+kkI8B>wD6<`Qz3dS~MoXW~W}lehEW|z4ka(JE;~l zsPeiO?GBUm zVto>9Wd+p7H3b82{S|r=o7^_b+0Djq$Fz4Z#p+V}-$ZTdzUoN+9L~D!h}cDz8qekA z6&7h7Ec)@R<1}dOprd;KgI8xV7KD?M*4n<_4xz*U1R9uul9U4^a z${7*}sl#(MVzON=1%YOOSS`g)DzZUQ+aBf(NfQgA(PSFn1+iur=`nz_b7cqvX#j)r zfy+T84A#mGDV<^0?$fERpxrJbGRv8swn;eJ&|ZU+^QP+Wq2{13%NB=)lKU*z`Lh+t zup)A=mlzC5)&ED?I|YXlh1-#y6g2+0M_$$7A+Pb6q*x&S0AuC;OlS7#Efs>FM{3uY{@ZSae+8AO@LJ zRHe}ZLisX8kiPn*jKVWC={+F-PI;+9LiGIb22$<;K~RJG7OA&I@yVX@Qr!)^ zmh{>LSX$ExE(yJv(M4sBje!a5sViQ2rAE3*i~QVCp_)~Xx94Jg z+`}-oVef8y!glmBb>6xlyQx|d-SwoZw^11vIBd3dOf=QCb9a${M3zoEztr8Fh#}Q2wIq5 ztsz68WegHuqr}Gp{WXd<2l4$iRfI8rI% z$ZRL#)pS+Y6YvTff=70MPjYpQWj*pLaC6q0Gt#_|7e>*x)Z#?^SwR^uZ%x_QpYp7n zgD`}q3Q7Dp>%kKS$=lRh<3Q};m*mgP_fN{|t5KVKk*9OPzeFzeW^>-6HXV(>oC?`eDc6R6uEBzyf26)7wFPGugd_ zZ8_uj$6vUzq%-mngyR$QM4k%TLX)X@+-6t9JLz?)v1vRghNv{C2)BK*y=tMby9wVWcz0xR2~g7Ixhet5B}ct3-Y+k~s*1;FpB+OmvCYgI;P%Znl$F8sbgZFC zVk^W+LUp+h;D`m1u-|*A5O|UYvMj0#&E%-P5}(Po3q6X5m@&iz>Qu6bv87StGS9NO zJfJ_+sXiBEv*1=Hc)2}a$|@ZveJhs!B@hVP(E1RpqP-2xGU^2I<09?Sm-x55dWL@z%VI^r!$)eD8st?add^{A+;H-moIlsB zoREYqUqOL+Ubom=$~o;?=f8nvmH?rG&=vnnvt2NaqD%t21m`Z({@c;r6sV#Hq*&-svw{)D)- zC`@cX^b-E$(x7x{_&^i$?kE96#gX84X+d-7wd%VeH2xx;V)rA~I;Pj;u_)<#j+4OC zNQ<=4fAIuo@c4E+xTV+$xO~-yx%18-)9q?-zE5~1cr|#2zpb(b2CVx(p6|e&N2uxT zLeM}6c1M!~N2srxP=@xia|-Kt#}s%4Y=g`Q(gUL<^J!e#Fw$}(_C-@gPU%svzntJs z72a`;%j!e9ea|~00pyt5EyoUma*9u*jB%>G;PK}<$_1g>qkx=Z@uz#E1ZK#Kg$Rp5 zWn~i&(3DstMys_@+3sU$Bo&wmike8dS;JJAlRhK>{TL+djg>NoouLsT8Cd57#g&!i z^066w`wo)teN;hFlpXl4Kqud?n)27% zH>hC?&|=Rj@HF}*=eW13EASHPW19$wQekB}B%8EynYo)|hvrg)0#TAwioP26;dBXr`g_-A)&xFXBO@t&*u$Ly<%?m-!?DPw#|0O(wk(Am-uHs4A8?11+OYzko z(t(2BzoAeu1_@FC6N?X~Q%ncx2Uurwu%#CP^XRG{H!;qF&vu~te;-Gg9K2?*{?i9r!~WsHZd_=e#`x# zd*X*KDiE5jd5Qym4r0ZDBKF`s&wUDR2N56!3od%Wop*Uy6z!1zlmq>cxWRtR{V6V} zPIs<|Z}WCEy7<8$MwIF2>sXw2)->lfWb|m{ZGMzgfShU^`MbfGSywR7W)2sKZ@tyd z`rf`JA6!hE$=K|SO3I#&5Q%UK*&#U7Rc8&6gF!6XQhAqTm|8%lmC9zua$ZVEO}og) zC~8FIzS(F4ndn8}Rnb2c6n%j923_Sq6Q!lcl|1Jy$!UhUp;{4PiB(o)Qdi zkW6z|s?m51E^H(9P`R!RW4d#fh@i6Dx2C^5_Chs2FVu&SIc15=!uytk*tL<=&IVdQ-{%-* zUsyn)`(i&C4vOhJ&bR@0_o_4>ksis{S|SwyF%f|&8)RFpUK``7G^PxYzx9J30=bU^ zVe0UMY9Wplja{3nZ_Z3B=Z~?2OY8#fU4^poaX2`CNnKE*y}cKwzn%&_#`QkHBw;s` zy|-qJzJ6q}UlaA#_P%xP@9yGKD}Rpt>MFLjcDy_s-A2w8cYPZZ`2cMy3&5`#;}>$= zl(*9fLSeercVYge8$v&8A>9*Tq?H-cZJG+s`!MTH6NU+n#@yBNY+*I}By?|h6t3%B~5A&g-`v#2e)RMXW5qsg?**D4I zT|&T{$L$>1&t;)tb>*6T2kIjwkeg`S%vZh;Ic2e-^J=)@uYsQ$^f;8KuURyB%gi6i z_VPn$>)XkBs5&7PeW&39$BjABnFq8))aQo1)j_Q87}B!`2-1Bhh~z*uS9o|JT)0u~vKUO}5 z@-iy`Br`x5&FaK!vg73e?}iDOT9_E8Qc+T*k<}w>>B> zC5*|LT#4US9_v&kOMimqph|8eg__y)FyFcsGd^ckuw~^r}O*Ayl7iDy?d)ZAwkb zb(L!m>+SUw=SB@5W83|VJ1pmLhZrdYbF0|cN$mBfji+=gIX5S z$(j2&*%|QISBEj<18PY9yKm;_y-IZdn(&y>MRrYJW?MiQE4Zj0jQ9$zMDOp(3vs$k zuTOoAxQ~V=5{eQH-`e+r=o^#kHtq$+j0{`Q_=D*K&#RvtGWL$rIxt*4hbH-yMwY;l zD|inhn=s2hDBd16Y2K{tNbDXI#?h6G$B4PEe0bHxz?cJMqQMUxmHB)EWE)gLisd3@ z=d^^QPfEa4DCO}lxZ@F5XmCDDb3D{FKaTXx%rVQ1dj-i|?9g&$RPz%7ts7eu()I38 zvljgIHgAhg>D|VDlr$L;OKqrJ$+I;7L~$Z3r~P_!(fOok{8+pQP7GB$QlpX3VotR5 zf`?Cgl-Uq-E0AcglTy<@FmwjuSwj{X*@9jDjiOl%Wjm|;pl)hA@Vi?>n>KiecP zrw}iy4RApF0-;CBdtz0$E-@z*y)ypH5*$#DeM`S`unfwT0!vxlB%#-pw204)`RA2t z+em}d07oMSH#HHGGTq~{?yemGJ1S&=dnqMVzMoBvV=MQH!2^+MFl>34k9sx2lY(*0 zj5)L|srs4$0}#$JsBzZIvc`gJHTCe&lI#V+C)Eu|k050^ zbWZ=zt8Q<~6M?v2K>_GM>sa#s0Hx%G(6=?QLYb6xVfZp^1Pn<@zQG^Dje4)+uaT%{ z4zUQHPJ8*rITQB?iLk4BeuRw56zP)H+*jSw_&Bz*{bp}|{ImXk_t}@yP zzw$zhOIpF`Gh||v3sBWqrOJ)fXTj@dh!_ip$LfYh_TriicKUBVJ@m@uc5UlJQ>`)h zt?^{WPOlEBdh>dgrY7`Ubu{e+mv+LQnrL6Dk$1Z7lWDTEhy}voK-D>2oDnlGXkV)2 z6a1Xhj{rCH&8pAJUPAhHw+1;vlZ5-`(U3Xcx*65RW+RZ_2pE&Kvq4gjhT@y=*Xor* zVvh#(k7s5Ia-*AqFMdeO?TZS&qX$*|CG%*!dkNf!U`Fp5@C5v823|9Q4AY+8`gwitYTs;syw|M?hUOYb7LT!T}3#`1ee+1>x67~E9?~sRrOydy2-}s=a zBM19hXnCH&VtvVMx}s0PY~LrUop)BvxQ$s=(6i_69joW51yvf?TPL5F=^YowEUt|$ zLv&BUM>Qp1wHX%gIw)bEG(hIBQYKe9G`m zFxd?r%l^4$hFmN8a>5mUl5dpTP>}|L)uX%5xvh0!1xP>#p9wsE?X2&<1nX zbT^@&z_RrC({R&uc!v7H3SP^z-o5vZxY@DCmR{!%SDU^rl%fq;nx)^XiX&P}hRE(U zAR6v^?$C3p-PK_4H{Qk@o~-&PXfVig{__w(`FYjH5gGs>9p~4x^*=vI1z~<6Y2p9M zJ+-9v%hMc2{lfVSubKy^Tp&4GER$4E%cB@SQmTnhRFsY1qwxm~g8-S;_Cv|K^Sxq9B3_ii-)hZQ`P^>*fI@xoXh3^_ zT-7{RtZ#O`emr08SU%k;fAEkm))#<}^QPu7%fPW(A&vqSq1h$}Vo_tryjekL8Pw*9K$nJt?ji@jZ? zA4NU+JTr^So2|LJhl?~uVfUzpR%pEOLIsSHuuf$?*5g#O2&+2wQI*C!e%R6qHW6lj zu?Kk+iNbF-DA{q_b?}33p(*LK$Iae}WUzd6sY{PKmmqYsYfa-^Y}&AXuTc#k+LN;( zkz*H}%zt(@r&=vT&v|K0!MI>dqNCD@9Hc^HNDOBPAhJk$yz3QynSI^*Co1OI-$72` z9{YaSBxC|j1}Xl{+8C~%4#KjdPqs3qg?zEaco2%_2KF} z{dg$YKh`=SX8kpxrF*iJVyrl6lCn4>In-gCKp>TPuUU_c6i7}-B%+7`(_p8$SSs#K z1aXuo0gLrSLh+wP(gj4A8?Dp+TPy1`r+4)(dl^{XK7k^W4R^Jgiuu zXt|LHVQv&cPauMS43#MH%!z-0m1=`_x=pK`>Um+6b)X)U`O#onK8?O{6@XHom1#n0 zwlZZ3S)yse57RPaj_EaxNqEb&jK9@_!>T;e9+9Q&3gk#f2D&g1l^^p%N1rbZV$06b z-bYya9_CEb2t*-G2gf2D3yT4ZXueGcQkg`s5fj-w{&HQoMwI9|yl2Ib5SY5R0--lh z((78XBTK2HZy@>Qj(O+U->>O}0 zR_#lI@T8f>JyP`iwfYaAXz!~Dr^bZV6opjwE(5N60mxsi;Xyt=KJIKIZUscT87@gS z@yu~Q!(n2i@@Dfqj-1pKyCpJOz*&2lgno+#Tt*UUcf5b3*DLq~RH!#M8*lpsC*VzN z+vjwljj8DJIJ4oNxs-J4)-xBxu3-$u=7D*zlHdQ5ZBdY@ghR9xqK6QlJ?P`64)lFF zQC8RnD*8O_-Mw8r8M!(3lP11-LmK9mjMjTvQ@0{RP6~W;oS+K0QmvSZX%F^#Y(x+C z)-Da4IIm+w2gby~@6IZ};BxbOAhft2%*iqyU+Y+)Hjyperd(FDsfIL$gABly8WM#& zxjjF&qYiImZbP4LP9g9m6BsmBMQ{qk@?CF~`f=Ny&l778`25=CnkP{u%nFE|{yOC~ zl5oC7`w7ibhfkRr#2FN9 z3r#wk^Q{7{&fAYe!6(Zi=ZZ`+h_v7OB*HHhFLGfjg4f79vvRF@Q}qv(X``;(D+F zw{Fm&QY0N|a*0d`KEQQ*`B5%9S#F#|&=i${2B;+Gn%fNymy4acr|e{g70u-<=UEL2 za|3jOZ@5oo^WERamAC>xtSbfN750*%ESlQ5^B^-itO0ZT3>&d!zx)N3Spi1@pFvfw zzj{9!ecM3;j*39I5`ORlaS|{IBtgNgM3F)-aTM96e{sy%&ww72>;=r^yzWaH@ky?m zV6v-XD2l++We7F($Qls5sXg$Yt5I`6Pztrgzf>2FCN+>%wEZ-^y!mBS9W>!Sn_Ln88w_cgHefB zljS7$a`P+^WYL``^a-NO?(z1ty9#dY2x{H{x7{fx35{__HrPV&wX^&cLC9#Y7>Mkg zMhc4c0Ms4aumYN9Qe6cHveSN1LJDH(tq?MCxlzBgyP*>dY5b%zY}T-(@l+kYF}A_< zsciG$W$Yd1m@KcJLYUVBnC6!h2Vm_1ZwUl0t*;b91TMvnD1WyVGwAZ*c0VtQ4PTq4`_nti^cAG#!Y+{{R^%h$eTMe;mtV?q zJI(%rR0WWMRm`jAOqmS%VlM737nb&LNkn<=5)#EZo>k`7IZ~(RrT0B2?##i*t`B(r zIvk%QLnIwhLWYY^P6}+viT76~Z!*c0iab(P_>xq`56WP!@WGcIH>S33nCcaq^j@1v z=!B4WG)otQ#6QgT3Ea%8Wh%7AN4-(0E$W`pH@FSALP?$_jtl^>LwLY+f935d7sF$D zO5e{SCfH5O`?5Ewp9z0mgN<@{AItW4pe`eg*=ueC)Kq@wvI7BDfSP1;?zR0Elfj0#<*+xJAvE1yegbYceLFX1$7j+fvX*rL3assV;e+cUW zZ0?&K&T)mGSamE#xX*Q~?H`>Nt`la$`y%>usP||wlix_bep;q2z)k5w$MB_OoCtNa)C|DrHaYQ%av>7J4T;@Ak6j* z*cbL@aJ8*ghSgjLTT1}3y!0>@+pG2BuKT3k%iEc`3&Wl)_!H)JWUVfc7z~^yh*@&r zjix7=^Tf6@9LNXJ9@4pArndb43A+OhjF%e zfMEXsB2ICjis6EmogfRF4A1>3WEL7YXk=c0hL^5}K)rzQkL^>@m>Dihr2a%2i|8iE z_AU<0nwO(A;e`b`-}bo!4R`J7_376|xMALBv-hO&p;ie|a-HxOaQN0}#;^gR^Hf2b_ z+~Ui@K_8Uu_Tb?s)MtqX%D|Pz)R78~NVw42=HwrsqE^_<67!lY!rMt&-nf5%T|8!5doZTN>*++nC!p zI_Xtt7U)W={lI^G~U`H(6$|NB_4w zkRf?Z9l`OA*b%tyvoR))mc|caA@Re^Q|q2VkPr!Qa_pj=k)(OMR|(Sb2we?dqR~Vs zsP1FOftDU(4sCR6paT4&BPdA%agc}Q?hXp1THurZ(qQay?_c&XVM4~!zlCBNnRb9+kd3iH~gIbOXQIS~v7+bPE#I1`bkeI46>LF<&yreP5y~3rO*zR$R zIfGKBJ`N{78dq5=15;E?q@4YmeB>loSG81>qfk{aW-fDlfEH$2Xrno+Tur>Xz1nuG zlB9Y`*4HYP8bfMcaxaI%5)vGD%D-1YY_7;@38Hd$heXfLy!n0^xtn}$n~k{$pN@BY z_por;V9Q$D++4l!6VFXrYg3Kbar%f<0F~ zMJEGjkR-vQAiVnFX%U1ESH6}Fu)Bz5@|{0aBveI*Q|4O``}&*C7fiDBp8>K$yMzBSW>)l)I#6hk)d9~H3i}-!NuQ2+dprg z!+>d@f7oQxB=AwGuefMz|CH^O|I-y$DLJQT(jom@aWL@pI+Zvw_a&K9{A*TLqe;Pj znoi!tNxssb7Xt{)(;q=8dV;K`LG6f4#ZYh$2Oat~iba(zZu=uWqs?Z`LqV4uHgfPE zsgP!(td?*nL&=16ibvKrGTQIQg;GG-?0d33LLR7NY=-6W7WM^5KhETAK|JK}CUD{I zKkUBpP73gbQ$UDInHU19TfuFa(|nc+8l3+UI~lvKX7%tEm_yBJ$cTc~aGWUc-af3S z^|3+OnC}E_1ADIdB85No?rem(jVrPJ+L#>&)Z8BGu;;DtrvHtSt6jkeA4X|2-i2uA z0>^!F`C=(DJB%1!4EBb=Uh7@5h3^i^{Z=S7G=;>0_W<%<%P~Lv?F0S+$8T=m6AamU z`e%OV%Nv4#W_~KOsmbdw-Mz<%@pPQWtDmrI!i+Ce7kW}B+rrP#$SvaIM$XOK?lR18 zG?psr0}fGV>7NHACA7kgH%Y9|fw-^=Kk!C_*7ukx()YJBIEt>>Avait!B{ozj=)Q= zXwv_vS@4Az|AFuUv}S+S7%HC~MaPQlv|Jsi9+v4P{PgyIO*|Hejpkb=|YP}~tXFG*HJ4tP= zBff^W*{2LD5t6S|z`@WjqO)$w1_&5@3Eb4x$!`mL{sv!gAtlJC&M(KhOXy?H_ig4l zw_FL7j#9Bx>IU(Rqo0ebhi98Z>Bs)S7XPLYV7ia6O?a!8Me0iKiH1@uZc_hDdr8ue zNfMzwJ!_7#OU1VlTo}_sj!mEPJz+`nsS#{L5>%Q~G)P$U1=_|u4OOCeW-F%8d5o^~ z@iMbQK)ov_MlA#BsQ^&>Y!WS`#Rgw5TCP&l`epRe`*6paFvVE0d~pW#9D3!Crm+wG zX_#${+#4ZD{xq!eLMV!-1K>@)b)v+#ofsP?x0`{{_4tBv7LP(C}oZAQwz;9RX%NpZ;)Yl z-AsdKV{;9a?Na5n7R%OfZr5f$+*Dc{0oQ%{>mdd_XPFbx?pEBPtOad;cKZXKnJ?#S zZ3l#my``{I0wYu{!}rGn;gkFQeSC5z>ABGT7*Zm(><~Kik{DwfZU3b|+UXB5L9@0X zh)`xZ-5rN)lnX`p^i>o|7g)5?eR-R%g6NxE+S=9+c$fkZ4Nz&?^2dUqG!1QRX3pl7zSjWh?clG@QU`#u~HLZ1MD?PsY}wzZ51*)O-K4?OlNEP;u8xW(uT1~kDH83UV66l4Asl%~ZWUR!D z)bEKL#+_=bQ`~Mqq*k|meT|dniZWAvhD{ zJpo#V-JSP!P_X(D7WLHAR8~a}X$VC^$gu=dA6QU_0~N$kwjnd}pkOnHAhjk#f{7K{ zB8)MkktAx8G#(9QJ+;AGM>yP9u#(0z_K$b+fkTbc-qj^-&MDziLjx$N>zR14N4ZPJ zMzX`LH%eM7${8jy)E$-EemPkHl`{#52P5G)%+RrNcc|<$Um+nKIHP3mg_+5=dQ!=J&Cf3Wxniv}c0PmeY_pmVe!| za0cnw{tzJIJ8S$UaKtuK?1rZQB1>tgoUbRpFtV+#Nh2fs)Xcs|d+WZ{$@gp^6B-xt zUy;?sOlaXfLlt^LFRY(=X+E)XwYPw(N~YFurr54|BywiHU$CulA2zr{qbi{*jAbS} ztV|a5JAUL%bDbr6HIsZD6@ z>;?bpDYL;cKTM}*D#!OLqV823m-7I6)y+2SN#O-v(pqip*DNl5Ni%#zQO_+9_^gHH zKG;Fo)pVvfep7*nU3R8BL|?(*EDLfGxOKglVj1B;87ZwD%n+liJ@ZJPf_HQHe?fm- z&idZA_%*G6ibSuYyWDp_n}rZ$`UkVu;AQl-wC*s7Id$HrBc%k`0*)wt4^J^UZ+G31 zaYuUZayILbVXDf|PxWYkOG2;&G^s_PB83N+{vBoJRd(TR#MPFJ6I-{$)4bM}LDg1V&%Ap~}CL&#vBg0k_kc=|WpQ`_OE zy)I`fMQLVib~g>EHvIr>ik{a*vLvs5!>d*0cw4;|%bK#}P@A5$W+5wDB{+jf_ zxb=62xYylJFCAV_*lNqX=THDUl*y*6EX`k2uEP}9DYz=d{9iB1Rtz!6V}Aw zzUTM7SSJ9~{NVm|eiX&o!gsK8<00!qtIo<`26Rb0U?u=CG z{oR2>yI#%iG9XM_BSgVh=gMs&3J{r4X8)5YdKnDeY1eWY6*K;nUI8h=HpdP%%&}Wb zG&6+$t-*(G?zgZbqydx`3j0HR&h9p)sh3KqA9j3Mz-M5mO17$s#Ftw+CSM$Z5NlbhfJbC|>MJz2ZKkCMf2J zuxF!BjKZRfg5;!>Tu457r>XemJat?sy|kJW`KGg*ql&>x)gAT(ZS&Tq)LJyDDv&El zAt+r%Lyo9P@o7?54d z&f;#)mlwAR0DV2qW}k?npq|U+$b~IT`p)3%v;b8g&H&qtu?Gp*HQ;**@OTNYzOSkH z45?0u6qdO^p1qa6-M}u|?Gp5?a%SB& z&MW?bngQ02Zl0FZ42w-^OM+li`h6l^rH#V?3q6-JByYUUv8}~bTRk3d>wnxBuUOJK zS%4QlUs=osn$>Ff*=M|r_YMJ&G9aaSSKsoZ)t%eF2 z6BWPxS$kp4itU0t<5V>kvEcV0HA^0k8ig*)aW^i#SDPBZ3(75!Q^ceUPa>1g)L@1) zme4O#r6Q--3M9(2Pb;rE3<;AO_$PDkEYExW07k7YH)j@nqD4YPldG9FOjP2}n=d3n zL<{1t{TY9hzk9_YP5WY zZR}2z95j8@xv0>mNeL4uZl{$u&W&VZ42OO+(GsY6Ben2?1c=(GGUSy8GUo*bqJX~4Lqez%h30YIz#~CCsfPJ7 zJe~99P@*oF3Y&5!P%KmkV$#=mH)no6LYolNEDUe%%4A?d<|yYm3e8+OBq6 zUtnD|fXPDE73j5{i>0R%+rxEnx8UqLR@?XOvdhSHDZCRwyyJ}&(7o;DhNj_QuRq-L z?s6GOUufI~$ADjxbxv?C_HE1G`{+kVJEjEvWKoxO-dC^7 zW7uc|1p{d(k?N$WXER_vyI>8yc^79+MxUo#+g)5vpR&tWi)_=WZ!+)@{?>kkK-ssv zcMp2U9mC|;BzD}kF6gZbW0YG`_4GcPn>*3)2cx3lUK!B<>m>`|&`Kx{xi^ne{rq>lfD zs4Nv+Xi9fJP4dTi3O}E28#h@R;8fi#>+5N;c9v~zwS2p!)bN}nKUHbv`qG`wK}Sfz z4Llu86+F?Z7*Rc=U1;$8hC$&(L%LXB;#*6Cwnn@{#18Q&rE}109i0CEEotAN>HbyDyJ3z zReVa4!W}mgVNXmdM5H7+N+G6f>;PcobDZKdi5zVliJ{;W=nqE$F3CDVO3F(d<(rgo3iKJNm7U5x%>KMrQGL8m zCP_dT^A52aW_K{~_95|ighvn115_b)=t2C_m9fi&MbER3kg_lYC!$G9k1G?N;@Q<} zdxX3k#%V!RZp1pL2i%V)ls@z42wREmGk%DKz%XolUjx7w81mfP)bzG<`SbJXL5C%1 z6L5z!v8C_w=_GTn(heaHLEp`bgh2h^NLUq;gzv4?j=7(kzVm0w1D_~mSo=Zvsh@-# zaOtKdI|6|yUycOKreL!hDq^CifenILTY^eQ;E^FK>=faJF>SYRVs-1#h0P9Q z)3{$+IB!SmP}Yq<0pxfn_AHzZtv50IX!OY&r(5s2Qkb=Z&gP|RioXo?+D~;Ke-=xq zC#}U)u9rE5#!;!wCIqWzpO*8bi17lR58uZzq?PIXbm4#a66%ea9+AM`<}pE z-4Ul>t-?iK^Ip;Nw67#kl0|Q=)*&OOXx#6W(ZazGh~Z_cQYwc*I*weim!rQ+BDOj^Lvt?3xIb%!ycJ}@4HD{Ko1I>qe4wQn_M^wWf_ z(Od=Tx{y6941T|(r4Y1|Gs^SHfPQ<|+FJAtf#;G+Lf!}>7B8N6Y*IsD(=u*P6XJq) z)m%YL^eld%zOR8z$0T93%}R2FXRC3Svyv9n>b6OGkSvC3^=ch3zud?*&GgBCc#xO| ztSE6x;kNa`6Yl~m(k!qO&wg)xx|3|Pcz`JAp_*fN;6)Zo?&@5N+72G@!Elm)HGO5? zx!d9hn_j{To`p)^i7K2sVCrsI!2&@$#U>;7Pj;mYl?Nxi!r}F ztwV|s%A+~yI?r%s=bfn-E6I(x*?xf+OdD9>?+9}lZ<}~&7d<(LTDhePv`i;{j&X0^ zBdi_Zb+Lm#jyP#w z^08F6RnowYHMV^^QLGFzq5FGXEfbZr92jE2aZ1g?AaWPSV7qweyg7f5LCXP zHo(3a`!izg^4P70%r@r}>Ew#GIlb2^I6Sqg9`)DTWA`VBV!Y|Jk}0i{OgYI0T-gVk z3ElnsR|uQfHa!hjV)6(9@@1QDbRNr-w3jU6jap^f@>J^HiovjFHoxI%D zyJ{KnVmbz{x38W~&9YRFm~80KBi^HIXx_+o(#wx6b-rpPrnZh+CU>V;9!6s=uf4%T zw0f8Hqh0A;SN)sn zmnoU2;Z|h<2kl;}*sCc;ORv$u2|>HR*VrJZI?bcLAEBtG77?QcuhZ@g1ViDS`dMKk zEY|jwlK|9>Ihb1iELt*bPE6r$Qm`{l*6f#aLresN5YtkNWrbG-<1bM32D%$W3uflhYQwBNY(PLN#GyeI=_y`n6c?mS8fG4DmYm$ULzwWfF z^5F%Y_)Rcq5XW6GV4*)Bt@UU(0Ms^ep8KePSz2t#41`(ODf%Ri(uv1`Q27%%Bsthm zOI+lNbyp!XZb&*;Tby1$f=?4TZ?4tYyRPSG2M4=cdQ&zAD zVYiK>QRJBG3_JQ~8Pg@Y#RzzV9{r^kHHiq*Q!e8BBIA1Z*5R5vBl>z%VdA6CUVQQI z%8x};iuO=gUo^)v`Rutj9ed$uG=1kquk}&S#*?ARBss(?dkfgsAlX2J7VH_rq}WjE zwt%OxIQd06i>iKmB!INv~VZHfIry= zel3(ElY}gYY&{#I_(wHRCX!}^nY+HZ`_HT`x6eATt3DRmR;sR4qq1xF^QiVfcE>Tk zq>%to;gpyt(iKQnz7&$_vQl@ufR5U-lprRHhrXDYhO&V<+dIbO$tWk z=c*{~j22Z2<%yZHk7b*Ny6xX2irV4a7(5!L4!z;Ub`^OrDx={-h?lD83r(J$_w?sv zTRUHyUR^!xJ&5}(0?AgyORvdEr*lQ`cjPPD``c7)BkE(wPVumAIG1}C{k5xw3^4N+ z=zN~9m3xd6LzxGAl0mDgVdI3W8)lJ%D_*JylRw_)*qknr(Y|PS$tgX(+@8_azNn`@jFjC z^d>rYWzn$tQL60d24H!1Mlg4V**lkI`JrwIVMzW3om0lx^CcA0vt~q&5i1Pt)7qqD z_^V_^Tu@EqPR2D!6739yikN8(399NpZS5^^Cq7&0&(!gI!_x}nsAIuY=kDAL2<+A| zZw00Aa{LEj9+9y+MY3H@%8w9NtLc==>?CRGggvWvAY&cNnTe0s9ybYpB1#U^!)@^l z5PBmUuT&;56in5PKjTBF=&NbnmbG=`-Z+S>!3lIl=3fRmqItw0rMxJB4@~1R^6fs% z<9P@*hY`6(!YT))`_gt2Y8$8Ka(6F z+&4T9wxXhP%9OfI2&9OI!Kg!ncQ4)9V)PJTiE^9k%c;3)$IC*yTG8VU^v(~_Ak?S_ zLV+8*;+TJCnF-h}h8mx3PvWIDJ*)3oDt?F)_y~RYt2Bsh_)m>+{4GFz@Fq70v-PlfCe4C?4Goy6H_+B$B*Js@E1xL=np%p_KXNK!u}#j>d26=4*t!Mx@4 zX9ukcY!^CTYRIx9oNR=H6hcqL3i*=QeLsjwcV(fgC}V}T>K6360*3louZ+b-{U%o7 zW>5!P$4&PDBq+7|REs6qD_fm0<@J23r|x#P)~F}^_5FGmld2#68mR6JdLoC|iW`Ls zRBwe1)=5pLh~X2?Rz`RmMh0X$P)jFh2`&z7J(q7n+&nK6qmBjWrV zN5{w-MPSI&**SG$hmAiG*LwD*BsLGJbx}(#l9mt8URT5CG>h*YB!fD95X%w!o%Zz` zsNVMf;p`oQM2*61y|#_hwr$(CZR@m7+qP}nwr$(Ct@KoKZ)K_`GfDn`wf}s(YQI?P zS?LKbaVQdEH5Hc0<{SPs(2hRK>F@eWcyB*WCg`|&{mDlU)}{0{6^6-d!VzU0^ws-L zi(^r;IJEZA9N&YBVz1y9ZHH+xjS%zvSEtXYzKCAL>>H8%LG~L1vs$P-KY)rtEIonN6}0U9ccp|Q&*wrR zqe8$dDL^wt{4XDy&F1q5aJ;7DANNRVY^*%Tm;N~;o;du?xy|^C{_|n7(C%oAG(%hp zXBJns7wgxiv{ud&oPC!9ezqD|`8GAfG+ZHeaus$HoN?8ZSlLTYXkCi1B-EF?)Dzdf zH?`aEULgj|OEFx&Lz$u7x>J4PVhLJtTsx*=68_)!se1H$SS>GI}wK$TVmO zRPUgX-qFfE$I3vf_>UEEgCASr-6)i6t}tK3s2AUyYY(nOa42SsogEWBr^*Cy7c^RT zUUb(zRy$2C)NpUX-Jzv|ymQ~c|9Nlu2}tV&_B(D2j{*Q-`~O+N{SWBfMV?>tNON*d zjW=jK7h4nZ+H}E{)4?iJqww0MWWJ=Ln{~@T9?AHzGNH4?c=g6%&kYB_E10-seMd(+ zYjR+~!*E|80YFyg=G)S5XkzG1)+~wR%d`%dm5XdOUg*670l09RCZH6wwbbwWf6t*vstTbzb?_@w~>zqMIB=!v1G-)@ipdmZ-h)(?6F#I=h zal@l086o%{<-Xm7SCtkWp+Y}KC;V2?g>di2a83t78~umz*_1Y)1EiD7k9vr0;M59! zzt@TRk6H;@C7$5TF)Jx}gV6o+Q-;e{xN5U}NWC^vIGjn?=IwMAo(pF%*GoS8V>MeH zns2iw0)jBmkVqeCX4_+imAt|${~y593aRU^*JNMGJGtE*rt zx@ZBc3;NcF<6F{h(0{YO5&Do&_n%md(4TD~S^04PG~4bzrZbEb56K1F*r^)y;q)`e z!2k^#Y4#nf1GudB+s_dMKk>mPoboU(n?a02i3&tTDC>bx%%n!N+V<>EY?46nlavJd zfks((0JP+KK@Iu|(%tAcDz*9kA$?@}o&%f1jE#qF%{nG46q{ON4W^^*wmw{^=DuZd zuuENvh*Mugt^z{!Xt&CC0^aaH+_Oj*#ENQC6;K9_x&@kz$XW@ z#2jXeV8e`I2>_i1YhrCtzDBa%%9i=ubZ3&HEltC?OvAV+nhvU;yiKy4lw zU|JHQ4>Be69Uk>o^gT`tk7Na}Ue%hqB>rA53MO3lCI5=Ste^7hYb+k#@-44)8Cvq% zT=Pmct4WYO$>9cyg@=ZauWsO+>2`+;ID+es#~Ipou<)pOx_^CktM+PgNG5xY@#@l` z##dL=- z+Pt?2(EO@55OL^XLH3!!DW63;hw2_pG!{E^>Peu-H0m`R4_~vLo@$sNc(D>t54l

2XFn4ZyWD)?H(~ivIxE1(PnG%L&wES=FvT7 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

RTLpiFj}bB@)D_O={P$# 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

R=EeJ*U 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

P38z zbnG*$GI#AMmE*Q!j8$*8NT^;2bC8Y>d&&+Z z805mZ*ueziFnct5XFBRiv7-~*RIAv;4hJhOv?XY9CeI0#$VX+$jXLQNsS11fm;?#j zMm-L;cdgV1`j8fbY6eg3bD?FXcAxx;lZR6zW&xbbU7&CD;~IST^25x?<{e+|QQGYv z)R@SmtVYY_dYXzES9_8eVuTnieaDkLwDzPZUc!Q;A2W}<5jE5l2T$=jMQza8axrASk@fCMPC z*1qoS*6#4{uT~xh24=CyrDndqPVTY|cAkb5X?X{nY|bvuvc1psbr*Ydo`q+4dVlcv z(nAPI#L0#UK<+FJ3}%l|gS f`%%T#4d#8}g?QW>~2_!35@?0KN(#fIs%N-18gk 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�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≧xxu7Rv2MpAw?QVe7`K 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

2XFn4ZyWD)?H(~ivIxE1(PnG%L&wES=FvT7 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 hNS6Ye+15-p_BQ`F1UeuUe4+^aV`>8w&=" ) +MESSAGE( STATUS ) diff --git a/external_src/raspicam-0.1.3/Changelog b/external_src/raspicam-0.1.3/Changelog new file mode 100644 index 0000000..f82bad1 --- /dev/null +++ b/external_src/raspicam-0.1.3/Changelog @@ -0,0 +1,33 @@ +0.1.3 + - Native support for BGR and RGB in opencv classes. No need to do conversion anymore. +0.1.2 + - Solved deadlock error in grab +0.1.1 + - Moved to c++11 mutex and condition_variables. Bug fixed that caused random dead lock condition in grab() +0.1.0 + - Bug fixed in release for RapiCam and RaspiCam_Cv +0.0.7 + - Added classes RaspiCam_Still and RaspiCam_Still_Cv for still camera mode +0.0.6 + - Bug ins cv camera corrected +0.0.5 + - getImageBuffeSize change by getImageBufferSize (sorry) + - Change in capture format. Now, it is able to capture in RGB at high speed. + - The second parameter of retrieve is now useless. Format must be specified in Raspicam::(set/get)Format before opening the camera and can not be change during operation. + - RaspiCam_Cv captures in BGR, which is obtained by converting from RGB. Therefore, performance drops to half repect to the RaspiCam in RGB mode when using 1280x960. +0.0.4 + - Added shutter speed camera control + - OpenCv set/get params are now scaled to [0,100] + - Added more command line options in test programs +0.0.3 + - Fixed error in color conversion (rgb and bgr were swapped) + - Added command line options in raspicam_test to adjust exposure + - Changes in RaspiCam_Cv so that exposure can be adjusted. Very simply. +0.0.2 + - Decoupled opening from the start of capture in RaspiCam if desired. RapiCam::open and RaspiCam::startCapture + - Added function RaspiCam::getId and RaspiCam_Cv::getId + - Added a new way to convert yuv2rgb which is a bit faster.Thanks to Stefan Gufman (gruffypuffy at gmail dot com) + - Added command line option -test_speed to utils programs (do not save images to memory) + - Removed useless code in private_impl +0.0.1 +Initial libary diff --git a/external_src/raspicam-0.1.3/README b/external_src/raspicam-0.1.3/README new file mode 100644 index 0000000..5aaf15a --- /dev/null +++ b/external_src/raspicam-0.1.3/README @@ -0,0 +1,207 @@ + +This library allows to use the Raspberry Pi Camera. + +* Main features: + - Provides class RaspiCam for easy and full control of the camera + - Provides class RaspiCam_Cv for easy control of the camera with OpenCV. + - Provides class RaspiCam_Still and RaspiCam_Still_Cv for controlling the camera in still mode + - Easy compilation/installation using cmake. + - No need to install development file of userland. Implementation is hidden. + - Many examples + +* ChangeLog +0.1.3 + - Native support for BGR and RGB in opencv classes. No need to do conversion anymore. +0.1.2 + - Solved deadlock error in grab +0.1.1 + - Moved to c++11 mutex and condition_variables. Bug fixed that caused random dead lock condition in grab() +0.1.0 + - Bug fixed in release for RapiCam and RaspiCam_Cv +0.0.7 + - Added classes RaspiCam_Still and RaspiCam_Still_Cv for still camera mode +0.0.6 + - Bug ins cv camera corrected +0.0.5 + - getImageBuffeSize change by getImageBufferSize (sorry) + - Change in capture format. Now, it is able to capture in RGB at high speed. + - The second parameter of retrieve is now useless. Format must be specified in Raspicam::(set/get)Format before opening the camera and can not be change during operation. + - RaspiCam_Cv captures in BGR, which is obtained by converting from RGB. Therefore, performance drops to half repect to the RaspiCam in RGB mode when using 1280x960. +0.0.4 + - Added shutter speed camera control + - OpenCv set/get params are now scaled to [0,100] + - Added more command line options in test programs +0.0.3 + - Fixed error in color conversion (rgb and bgr were swapped) + - Added command line options in raspicam_test to adjust exposure + - Changes in RaspiCam_Cv so that exposure can be adjusted. Very simply. +0.0.2 + - Decoupled opening from the start of capture in RaspiCam if desired. RapiCam::open and RaspiCam::startCapture + - Added function RaspiCam::getId and RaspiCam_Cv::getId + - Added a new way to convert yuv2rgb which is a bit faster.Thanks to Stefan Gufman (gruffypuffy at gmail dot com) + - Added command line option -test_speed to utils programs (do not save images to memory) + - Removed useless code in private_impl + +0.0.1 +Initial libary + + +* Compiling + +Download the file to your raspberry. Then, uncompress the file and compile + +tar xvzf raspicamxx.tgz +cd raspicamxx +mkdir build +cd build +cmake .. + +At this point you'll see something like +-- CREATE OPENCV MODULE=1 +-- CMAKE_INSTALL_PREFIX=/usr/local +-- REQUIRED_LIBRARIES=/opt/vc/lib/libmmal_core.so;/opt/vc/lib/libmmal_util.so;/opt/vc/lib/libmmal.so +-- Change a value with: cmake -D= +-- +-- Configuring done +-- Generating done +-- Build files have been written to: /home/pi/raspicam/trunk/build + +If OpenCV development files are installed in your system, then you see +-- CREATE OPENCV MODULE=1 +otherwise this option will be 0 and the opencv module of the library will not be compiled. + +Finally compile and install +make +sudo make install + + +After that, you have the programs raspicam_test and raspicam_cv_test (if opencv was enabled). +Run the first program to check that compilation is ok. + +You can check that the library has installed the header files under /usr/local/lib/raspicam , and the libraries in +/usr/local/lib/libraspicam.so and /usr/local/lib/libraspicam_cv.so (if opencv support enabled) + +* Using it in your projects + +We provide a simple example to use the library. Create a directory for our own project. + +First create a file with the name simpletest_raspicam.cpp and add the following code + +/** +*/ +#include +#include +#include +#include +using namespace std; + +int main ( int argc,char **argv ) { + raspicam::RaspiCam Camera; //Cmaera object + //Open camera + cout<<"Opening Camera..."< +#include +#include +using namespace std; + +int main ( int argc,char **argv ) { + + time_t timer_begin,timer_end; + raspicam::RaspiCam_Cv Camera; + cv::Mat image; + int nCount=100; + //set camera params + Camera.set( CV_CAP_PROP_FORMAT, CV_8UC1 ); + //Open camera + cout<<"Opening Camera..."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 literal 0 HcmV?d00001 diff --git a/external_src/raspicam-0.1.3/build/CMakeFiles/2.8.12.2/CMakeDetermineCompilerABI_CXX.bin b/external_src/raspicam-0.1.3/build/CMakeFiles/2.8.12.2/CMakeDetermineCompilerABI_CXX.bin new file mode 100755 index 0000000000000000000000000000000000000000..273b9bec03eba99856d45e9792c92dc36cfbd2c2 GIT binary patch literal 8353 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 & 0x00FF) +# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF) +# define COMPILER_VERSION_PATCH HEX(__CODEGEARC_VERSION__ & 0xFFFF) + +#elif defined(__BORLANDC__) +# define COMPILER_ID "Borland" + /* __BORLANDC__ = 0xVRR */ +# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8) +# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF) + +#elif defined(__WATCOMC__) +# define COMPILER_ID "Watcom" + /* __WATCOMC__ = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100) +# define COMPILER_VERSION_MINOR DEC(__WATCOMC__ % 100) + +#elif defined(__SUNPRO_C) +# define COMPILER_ID "SunPro" +# if __SUNPRO_C >= 0x5100 + /* __SUNPRO_C = 0xVRRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C>>12) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_C>>4 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_C & 0xF) +# else + /* __SUNPRO_C = 0xVRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C>>8) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_C>>4 & 0xF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_C & 0xF) +# endif + +#elif defined(__HP_cc) +# define COMPILER_ID "HP" + /* __HP_cc = VVRRPP */ +# define COMPILER_VERSION_MAJOR DEC(__HP_cc/10000) +# define COMPILER_VERSION_MINOR DEC(__HP_cc/100 % 100) +# define COMPILER_VERSION_PATCH DEC(__HP_cc % 100) + +#elif defined(__DECC) +# define COMPILER_ID "Compaq" + /* __DECC_VER = VVRRTPPPP */ +# define COMPILER_VERSION_MAJOR DEC(__DECC_VER/10000000) +# define COMPILER_VERSION_MINOR DEC(__DECC_VER/100000 % 100) +# define COMPILER_VERSION_PATCH DEC(__DECC_VER % 10000) + +#elif defined(__IBMC__) +# if defined(__COMPILER_VER__) +# define COMPILER_ID "zOS" +# else +# if __IBMC__ >= 800 +# define COMPILER_ID "XL" +# else +# define COMPILER_ID "VisualAge" +# endif + /* __IBMC__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10) +# endif + +#elif defined(__PGI) +# define COMPILER_ID "PGI" +# define COMPILER_VERSION_MAJOR DEC(__PGIC__) +# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__) +# if defined(__PGIC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__) +# endif + +#elif defined(_CRAYC) +# define COMPILER_ID "Cray" +# define COMPILER_VERSION_MAJOR DEC(_RELEASE) +# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR) + +#elif defined(__TI_COMPILER_VERSION__) +# define COMPILER_ID "TI" + /* __TI_COMPILER_VERSION__ = VVVRRRPPP */ +# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000) +# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000) +# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000) + +#elif defined(__TINYC__) +# define COMPILER_ID "TinyCC" + +#elif defined(__SCO_VERSION__) +# define COMPILER_ID "SCO" + +#elif defined(__GNUC__) +# define COMPILER_ID "GNU" +# define COMPILER_VERSION_MAJOR DEC(__GNUC__) +# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__) +# if defined(__GNUC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +# endif + +#elif defined(_MSC_VER) +# define COMPILER_ID "MSVC" + /* _MSC_VER = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100) +# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100) +# if defined(_MSC_FULL_VER) +# if _MSC_VER >= 1400 + /* _MSC_FULL_VER = VVRRPPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000) +# else + /* _MSC_FULL_VER = VVRRPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000) +# endif +# endif +# if defined(_MSC_BUILD) +# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD) +# endif + +/* Analog VisualDSP++ >= 4.5.6 */ +#elif defined(__VISUALDSPVERSION__) +# define COMPILER_ID "ADSP" + /* __VISUALDSPVERSION__ = 0xVVRRPP00 */ +# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24) +# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8 & 0xFF) + +/* Analog VisualDSP++ < 4.5.6 */ +#elif defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__) +# define COMPILER_ID "ADSP" + +/* IAR Systems compiler for embedded systems. + http://www.iar.com */ +#elif defined(__IAR_SYSTEMS_ICC__ ) || defined(__IAR_SYSTEMS_ICC) +# define COMPILER_ID "IAR" + +/* sdcc, the small devices C compiler for embedded systems, + http://sdcc.sourceforge.net */ +#elif defined(SDCC) +# define COMPILER_ID "SDCC" + /* SDCC = VRP */ +# define COMPILER_VERSION_MAJOR DEC(SDCC/100) +# define COMPILER_VERSION_MINOR DEC(SDCC/10 % 10) +# define COMPILER_VERSION_PATCH DEC(SDCC % 10) + +#elif defined(_SGI_COMPILER_VERSION) || defined(_COMPILER_VERSION) +# define COMPILER_ID "MIPSpro" +# if defined(_SGI_COMPILER_VERSION) + /* _SGI_COMPILER_VERSION = VRP */ +# define COMPILER_VERSION_MAJOR DEC(_SGI_COMPILER_VERSION/100) +# define COMPILER_VERSION_MINOR DEC(_SGI_COMPILER_VERSION/10 % 10) +# define COMPILER_VERSION_PATCH DEC(_SGI_COMPILER_VERSION % 10) +# else + /* _COMPILER_VERSION = VRP */ +# define COMPILER_VERSION_MAJOR DEC(_COMPILER_VERSION/100) +# define COMPILER_VERSION_MINOR DEC(_COMPILER_VERSION/10 % 10) +# define COMPILER_VERSION_PATCH DEC(_COMPILER_VERSION % 10) +# endif + +/* This compiler is either not known or is too old to define an + identification macro. Try to identify the platform and guess that + it is the native compiler. */ +#elif defined(__sgi) +# define COMPILER_ID "MIPSpro" + +#elif defined(__hpux) || defined(__hpua) +# define COMPILER_ID "HP" + +#else /* unknown compiler */ +# define COMPILER_ID "" + +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]"; + +/* Identify known platforms by name. */ +#if defined(__linux) || defined(__linux__) || defined(linux) +# define PLATFORM_ID "Linux" + +#elif defined(__CYGWIN__) +# define PLATFORM_ID "Cygwin" + +#elif defined(__MINGW32__) +# define PLATFORM_ID "MinGW" + +#elif defined(__APPLE__) +# define PLATFORM_ID "Darwin" + +#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +# define PLATFORM_ID "Windows" + +#elif defined(__FreeBSD__) || defined(__FreeBSD) +# define PLATFORM_ID "FreeBSD" + +#elif defined(__NetBSD__) || defined(__NetBSD) +# define PLATFORM_ID "NetBSD" + +#elif defined(__OpenBSD__) || defined(__OPENBSD) +# define PLATFORM_ID "OpenBSD" + +#elif defined(__sun) || defined(sun) +# define PLATFORM_ID "SunOS" + +#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__) +# define PLATFORM_ID "AIX" + +#elif defined(__sgi) || defined(__sgi__) || defined(_SGI) +# define PLATFORM_ID "IRIX" + +#elif defined(__hpux) || defined(__hpux__) +# define PLATFORM_ID "HP-UX" + +#elif defined(__HAIKU__) +# define PLATFORM_ID "Haiku" + +#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS) +# define PLATFORM_ID "BeOS" + +#elif defined(__QNX__) || defined(__QNXNTO__) +# define PLATFORM_ID "QNX" + +#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__) +# define PLATFORM_ID "Tru64" + +#elif defined(__riscos) || defined(__riscos__) +# define PLATFORM_ID "RISCos" + +#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__) +# define PLATFORM_ID "SINIX" + +#elif defined(__UNIX_SV__) +# define PLATFORM_ID "UNIX_SV" + +#elif defined(__bsdos__) +# define PLATFORM_ID "BSDOS" + +#elif defined(_MPRAS) || defined(MPRAS) +# define PLATFORM_ID "MP-RAS" + +#elif defined(__osf) || defined(__osf__) +# define PLATFORM_ID "OSF1" + +#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv) +# define PLATFORM_ID "SCO_SV" + +#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX) +# define PLATFORM_ID "ULTRIX" + +#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX) +# define PLATFORM_ID "Xenix" + +#else /* unknown platform */ +# define PLATFORM_ID "" + +#endif + +/* For windows compilers MSVC and Intel we can determine + the architecture of the compiler being used. This is because + the compilers do not have flags that can change the architecture, + but rather depend on which compiler is being used +*/ +#if defined(_WIN32) && defined(_MSC_VER) +# if defined(_M_IA64) +# define ARCHITECTURE_ID "IA64" + +# elif defined(_M_X64) || defined(_M_AMD64) +# define ARCHITECTURE_ID "x64" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# elif defined(_M_ARM) +# define ARCHITECTURE_ID "ARM" + +# elif defined(_M_MIPS) +# define ARCHITECTURE_ID "MIPS" + +# elif defined(_M_SH) +# define ARCHITECTURE_ID "SHx" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#else +# define ARCHITECTURE_ID "" +#endif + +/* Convert integer to decimal digit literals. */ +#define DEC(n) \ + ('0' + (((n) / 10000000)%10)), \ + ('0' + (((n) / 1000000)%10)), \ + ('0' + (((n) / 100000)%10)), \ + ('0' + (((n) / 10000)%10)), \ + ('0' + (((n) / 1000)%10)), \ + ('0' + (((n) / 100)%10)), \ + ('0' + (((n) / 10)%10)), \ + ('0' + ((n) % 10)) + +/* Convert integer to hex digit literals. */ +#define HEX(n) \ + ('0' + ((n)>>28 & 0xF)), \ + ('0' + ((n)>>24 & 0xF)), \ + ('0' + ((n)>>20 & 0xF)), \ + ('0' + ((n)>>16 & 0xF)), \ + ('0' + ((n)>>12 & 0xF)), \ + ('0' + ((n)>>8 & 0xF)), \ + ('0' + ((n)>>4 & 0xF)), \ + ('0' + ((n) & 0xF)) + +/* Construct a string literal encoding the version number components. */ +#ifdef COMPILER_VERSION_MAJOR +char const info_version[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[', + COMPILER_VERSION_MAJOR, +# ifdef COMPILER_VERSION_MINOR + '.', COMPILER_VERSION_MINOR, +# ifdef COMPILER_VERSION_PATCH + '.', COMPILER_VERSION_PATCH, +# ifdef COMPILER_VERSION_TWEAK + '.', COMPILER_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]"; +char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]"; + + + +/*--------------------------------------------------------------------------*/ + +#ifdef ID_VOID_MAIN +void main() {} +#else +int main(int argc, char* argv[]) +{ + int require = 0; + require += info_compiler[argc]; + require += info_platform[argc]; + require += info_arch[argc]; +#ifdef COMPILER_VERSION_MAJOR + require += info_version[argc]; +#endif + (void)argv; + return require; +} +#endif diff --git a/external_src/raspicam-0.1.3/build/CMakeFiles/2.8.12.2/CompilerIdC/a.out b/external_src/raspicam-0.1.3/build/CMakeFiles/2.8.12.2/CompilerIdC/a.out new file mode 100755 index 0000000000000000000000000000000000000000..a45b7893a511c098e7c52575e17a0b49170ec6cc GIT binary patch literal 8408 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 cXZNU?Gp%#1Yv^gsu>24 & 0x00FF) +# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF) +# define COMPILER_VERSION_PATCH HEX(__CODEGEARC_VERSION__ & 0xFFFF) + +#elif defined(__BORLANDC__) +# define COMPILER_ID "Borland" + /* __BORLANDC__ = 0xVRR */ +# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8) +# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF) + +#elif defined(__WATCOMC__) +# define COMPILER_ID "Watcom" + /* __WATCOMC__ = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100) +# define COMPILER_VERSION_MINOR DEC(__WATCOMC__ % 100) + +#elif defined(__SUNPRO_CC) +# define COMPILER_ID "SunPro" +# if __SUNPRO_CC >= 0x5100 + /* __SUNPRO_CC = 0xVRRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>12) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) +# else + /* __SUNPRO_CC = 0xVRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>8) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) +# endif + +#elif defined(__HP_aCC) +# define COMPILER_ID "HP" + /* __HP_aCC = VVRRPP */ +# define COMPILER_VERSION_MAJOR DEC(__HP_aCC/10000) +# define COMPILER_VERSION_MINOR DEC(__HP_aCC/100 % 100) +# define COMPILER_VERSION_PATCH DEC(__HP_aCC % 100) + +#elif defined(__DECCXX) +# define COMPILER_ID "Compaq" + /* __DECCXX_VER = VVRRTPPPP */ +# define COMPILER_VERSION_MAJOR DEC(__DECCXX_VER/10000000) +# define COMPILER_VERSION_MINOR DEC(__DECCXX_VER/100000 % 100) +# define COMPILER_VERSION_PATCH DEC(__DECCXX_VER % 10000) + +#elif defined(__IBMCPP__) +# if defined(__COMPILER_VER__) +# define COMPILER_ID "zOS" +# else +# if __IBMCPP__ >= 800 +# define COMPILER_ID "XL" +# else +# define COMPILER_ID "VisualAge" +# endif + /* __IBMCPP__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) +# endif + +#elif defined(__PGI) +# define COMPILER_ID "PGI" +# define COMPILER_VERSION_MAJOR DEC(__PGIC__) +# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__) +# if defined(__PGIC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__) +# endif + +#elif defined(_CRAYC) +# define COMPILER_ID "Cray" +# define COMPILER_VERSION_MAJOR DEC(_RELEASE) +# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR) + +#elif defined(__TI_COMPILER_VERSION__) +# define COMPILER_ID "TI" + /* __TI_COMPILER_VERSION__ = VVVRRRPPP */ +# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000) +# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000) +# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000) + +#elif defined(__SCO_VERSION__) +# define COMPILER_ID "SCO" + +#elif defined(__GNUC__) +# define COMPILER_ID "GNU" +# define COMPILER_VERSION_MAJOR DEC(__GNUC__) +# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__) +# if defined(__GNUC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +# endif + +#elif defined(_MSC_VER) +# define COMPILER_ID "MSVC" + /* _MSC_VER = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100) +# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100) +# if defined(_MSC_FULL_VER) +# if _MSC_VER >= 1400 + /* _MSC_FULL_VER = VVRRPPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000) +# else + /* _MSC_FULL_VER = VVRRPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000) +# endif +# endif +# if defined(_MSC_BUILD) +# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD) +# endif + +/* Analog VisualDSP++ >= 4.5.6 */ +#elif defined(__VISUALDSPVERSION__) +# define COMPILER_ID "ADSP" + /* __VISUALDSPVERSION__ = 0xVVRRPP00 */ +# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24) +# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8 & 0xFF) + +/* Analog VisualDSP++ < 4.5.6 */ +#elif defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__) +# define COMPILER_ID "ADSP" + +/* IAR Systems compiler for embedded systems. + http://www.iar.com */ +#elif defined(__IAR_SYSTEMS_ICC__ ) || defined(__IAR_SYSTEMS_ICC) +# define COMPILER_ID "IAR" + +#elif defined(_SGI_COMPILER_VERSION) || defined(_COMPILER_VERSION) +# define COMPILER_ID "MIPSpro" +# if defined(_SGI_COMPILER_VERSION) + /* _SGI_COMPILER_VERSION = VRP */ +# define COMPILER_VERSION_MAJOR DEC(_SGI_COMPILER_VERSION/100) +# define COMPILER_VERSION_MINOR DEC(_SGI_COMPILER_VERSION/10 % 10) +# define COMPILER_VERSION_PATCH DEC(_SGI_COMPILER_VERSION % 10) +# else + /* _COMPILER_VERSION = VRP */ +# define COMPILER_VERSION_MAJOR DEC(_COMPILER_VERSION/100) +# define COMPILER_VERSION_MINOR DEC(_COMPILER_VERSION/10 % 10) +# define COMPILER_VERSION_PATCH DEC(_COMPILER_VERSION % 10) +# endif + +/* This compiler is either not known or is too old to define an + identification macro. Try to identify the platform and guess that + it is the native compiler. */ +#elif defined(__sgi) +# define COMPILER_ID "MIPSpro" + +#elif defined(__hpux) || defined(__hpua) +# define COMPILER_ID "HP" + +#else /* unknown compiler */ +# define COMPILER_ID "" + +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]"; + +/* Identify known platforms by name. */ +#if defined(__linux) || defined(__linux__) || defined(linux) +# define PLATFORM_ID "Linux" + +#elif defined(__CYGWIN__) +# define PLATFORM_ID "Cygwin" + +#elif defined(__MINGW32__) +# define PLATFORM_ID "MinGW" + +#elif defined(__APPLE__) +# define PLATFORM_ID "Darwin" + +#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +# define PLATFORM_ID "Windows" + +#elif defined(__FreeBSD__) || defined(__FreeBSD) +# define PLATFORM_ID "FreeBSD" + +#elif defined(__NetBSD__) || defined(__NetBSD) +# define PLATFORM_ID "NetBSD" + +#elif defined(__OpenBSD__) || defined(__OPENBSD) +# define PLATFORM_ID "OpenBSD" + +#elif defined(__sun) || defined(sun) +# define PLATFORM_ID "SunOS" + +#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__) +# define PLATFORM_ID "AIX" + +#elif defined(__sgi) || defined(__sgi__) || defined(_SGI) +# define PLATFORM_ID "IRIX" + +#elif defined(__hpux) || defined(__hpux__) +# define PLATFORM_ID "HP-UX" + +#elif defined(__HAIKU__) +# define PLATFORM_ID "Haiku" + +#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS) +# define PLATFORM_ID "BeOS" + +#elif defined(__QNX__) || defined(__QNXNTO__) +# define PLATFORM_ID "QNX" + +#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__) +# define PLATFORM_ID "Tru64" + +#elif defined(__riscos) || defined(__riscos__) +# define PLATFORM_ID "RISCos" + +#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__) +# define PLATFORM_ID "SINIX" + +#elif defined(__UNIX_SV__) +# define PLATFORM_ID "UNIX_SV" + +#elif defined(__bsdos__) +# define PLATFORM_ID "BSDOS" + +#elif defined(_MPRAS) || defined(MPRAS) +# define PLATFORM_ID "MP-RAS" + +#elif defined(__osf) || defined(__osf__) +# define PLATFORM_ID "OSF1" + +#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv) +# define PLATFORM_ID "SCO_SV" + +#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX) +# define PLATFORM_ID "ULTRIX" + +#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX) +# define PLATFORM_ID "Xenix" + +#else /* unknown platform */ +# define PLATFORM_ID "" + +#endif + +/* For windows compilers MSVC and Intel we can determine + the architecture of the compiler being used. This is because + the compilers do not have flags that can change the architecture, + but rather depend on which compiler is being used +*/ +#if defined(_WIN32) && defined(_MSC_VER) +# if defined(_M_IA64) +# define ARCHITECTURE_ID "IA64" + +# elif defined(_M_X64) || defined(_M_AMD64) +# define ARCHITECTURE_ID "x64" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# elif defined(_M_ARM) +# define ARCHITECTURE_ID "ARM" + +# elif defined(_M_MIPS) +# define ARCHITECTURE_ID "MIPS" + +# elif defined(_M_SH) +# define ARCHITECTURE_ID "SHx" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#else +# define ARCHITECTURE_ID "" +#endif + +/* Convert integer to decimal digit literals. */ +#define DEC(n) \ + ('0' + (((n) / 10000000)%10)), \ + ('0' + (((n) / 1000000)%10)), \ + ('0' + (((n) / 100000)%10)), \ + ('0' + (((n) / 10000)%10)), \ + ('0' + (((n) / 1000)%10)), \ + ('0' + (((n) / 100)%10)), \ + ('0' + (((n) / 10)%10)), \ + ('0' + ((n) % 10)) + +/* Convert integer to hex digit literals. */ +#define HEX(n) \ + ('0' + ((n)>>28 & 0xF)), \ + ('0' + ((n)>>24 & 0xF)), \ + ('0' + ((n)>>20 & 0xF)), \ + ('0' + ((n)>>16 & 0xF)), \ + ('0' + ((n)>>12 & 0xF)), \ + ('0' + ((n)>>8 & 0xF)), \ + ('0' + ((n)>>4 & 0xF)), \ + ('0' + ((n) & 0xF)) + +/* Construct a string literal encoding the version number components. */ +#ifdef COMPILER_VERSION_MAJOR +char const info_version[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[', + COMPILER_VERSION_MAJOR, +# ifdef COMPILER_VERSION_MINOR + '.', COMPILER_VERSION_MINOR, +# ifdef COMPILER_VERSION_PATCH + '.', COMPILER_VERSION_PATCH, +# ifdef COMPILER_VERSION_TWEAK + '.', COMPILER_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]"; +char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]"; + + + +/*--------------------------------------------------------------------------*/ + +int main(int argc, char* argv[]) +{ + int require = 0; + require += info_compiler[argc]; + require += info_platform[argc]; +#ifdef COMPILER_VERSION_MAJOR + require += info_version[argc]; +#endif + (void)argv; + return require; +} diff --git a/external_src/raspicam-0.1.3/build/CMakeFiles/2.8.12.2/CompilerIdCXX/a.out b/external_src/raspicam-0.1.3/build/CMakeFiles/2.8.12.2/CompilerIdCXX/a.out new file mode 100755 index 0000000000000000000000000000000000000000..8b271d6a2152253e61f904517ec415131ec490fa GIT binary patch literal 8433 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 literal 0 HcmV?d00001 diff --git a/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeDirectoryInformation.cmake b/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeDirectoryInformation.cmake new file mode 100644 index 0000000..24120d7 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeDirectoryInformation.cmake @@ -0,0 +1,16 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Relative path conversion top directories. +SET(CMAKE_RELATIVE_PATH_TOP_SOURCE "/home/ubuntu/Nomad/external_src/raspicam-0.1.3") +SET(CMAKE_RELATIVE_PATH_TOP_BINARY "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build") + +# Force unix paths in dependencies. +SET(CMAKE_FORCE_UNIX_PATHS 1) + + +# The C and CXX include file regular expressions for this directory. +SET(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$") +SET(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$") +SET(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN}) +SET(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN}) diff --git a/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeOutput.log b/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeOutput.log new file mode 100644 index 0000000..28a3e1e --- /dev/null +++ b/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeOutput.log @@ -0,0 +1,265 @@ +The system is: Linux - 3.18.0-20-rpi2 - armv7l +Compiling the C compiler identification source file "CMakeCCompilerId.c" succeeded. +Compiler: /usr/bin/cc +Build flags: +Id flags: + +The output was: +0 + + +Compilation of the C compiler identification source "CMakeCCompilerId.c" produced "a.out" + +The C compiler identification is GNU, found in "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/2.8.12.2/CompilerIdC/a.out" + +Compiling the CXX compiler identification source file "CMakeCXXCompilerId.cpp" succeeded. +Compiler: /usr/bin/c++ +Build flags: +Id flags: + +The output was: +0 + + +Compilation of the CXX compiler identification source "CMakeCXXCompilerId.cpp" produced "a.out" + +The CXX compiler identification is GNU, found in "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/2.8.12.2/CompilerIdCXX/a.out" + +Determining if the C compiler works passed with the following output: +Change Dir: /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp + +Run Build Command:/usr/bin/make "cmTryCompileExec2659741268/fast" +/usr/bin/make -f CMakeFiles/cmTryCompileExec2659741268.dir/build.make CMakeFiles/cmTryCompileExec2659741268.dir/build +make[1]: Entering directory `/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp' +/usr/bin/cmake -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp/CMakeFiles 1 +Building C object CMakeFiles/cmTryCompileExec2659741268.dir/testCCompiler.c.o +/usr/bin/cc -o CMakeFiles/cmTryCompileExec2659741268.dir/testCCompiler.c.o -c /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp/testCCompiler.c +Linking C executable cmTryCompileExec2659741268 +/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTryCompileExec2659741268.dir/link.txt --verbose=1 +/usr/bin/cc CMakeFiles/cmTryCompileExec2659741268.dir/testCCompiler.c.o -o cmTryCompileExec2659741268 -rdynamic +make[1]: Leaving directory `/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp' + + +Detecting C compiler ABI info compiled with the following output: +Change Dir: /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp + +Run Build Command:/usr/bin/make "cmTryCompileExec781799643/fast" +/usr/bin/make -f CMakeFiles/cmTryCompileExec781799643.dir/build.make CMakeFiles/cmTryCompileExec781799643.dir/build +make[1]: Entering directory `/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp' +/usr/bin/cmake -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp/CMakeFiles 1 +Building C object CMakeFiles/cmTryCompileExec781799643.dir/CMakeCCompilerABI.c.o +/usr/bin/cc -o CMakeFiles/cmTryCompileExec781799643.dir/CMakeCCompilerABI.c.o -c /usr/share/cmake-2.8/Modules/CMakeCCompilerABI.c +Linking C executable cmTryCompileExec781799643 +/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTryCompileExec781799643.dir/link.txt --verbose=1 +/usr/bin/cc -v CMakeFiles/cmTryCompileExec781799643.dir/CMakeCCompilerABI.c.o -o cmTryCompileExec781799643 -rdynamic +Using built-in specs. +COLLECT_GCC=/usr/bin/cc +COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/4.8/lto-wrapper +Target: arm-linux-gnueabihf +Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.8.4-2ubuntu1~14.04' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --disable-libitm --disable-libquadmath --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-armhf/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-armhf --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-armhf --with-arch-directory=arm --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --enable-multilib --disable-sjlj-exceptions --with-arch=armv7-a --with-fpu=vfpv3-d16 --with-float=hard --with-mode=thumb --disable-werror --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf +Thread model: posix +gcc version 4.8.4 (Ubuntu/Linaro 4.8.4-2ubuntu1~14.04) +COMPILER_PATH=/usr/lib/gcc/arm-linux-gnueabihf/4.8/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/:/usr/lib/gcc/arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/:/usr/lib/gcc/arm-linux-gnueabihf/ +LIBRARY_PATH=/usr/lib/gcc/arm-linux-gnueabihf/4.8/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../../lib/:/lib/arm-linux-gnueabihf/:/lib/../lib/:/usr/lib/arm-linux-gnueabihf/:/usr/lib/../lib/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../:/lib/:/usr/lib/ +COLLECT_GCC_OPTIONS='-v' '-o' 'cmTryCompileExec781799643' '-rdynamic' '-march=armv7-a' '-mfloat-abi=hard' '-mfpu=vfpv3-d16' '-mthumb' '-mtls-dialect=gnu' + /usr/lib/gcc/arm-linux-gnueabihf/4.8/collect2 --sysroot=/ --build-id --eh-frame-hdr -export-dynamic -dynamic-linker /lib/ld-linux-armhf.so.3 -X --hash-style=gnu --as-needed -m armelf_linux_eabi -z relro -o cmTryCompileExec781799643 /usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/crt1.o /usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/crti.o /usr/lib/gcc/arm-linux-gnueabihf/4.8/crtbegin.o -L/usr/lib/gcc/arm-linux-gnueabihf/4.8 -L/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf -L/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../../lib -L/lib/arm-linux-gnueabihf -L/lib/../lib -L/usr/lib/arm-linux-gnueabihf -L/usr/lib/../lib -L/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../.. CMakeFiles/cmTryCompileExec781799643.dir/CMakeCCompilerABI.c.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/arm-linux-gnueabihf/4.8/crtend.o /usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/crtn.o +make[1]: Leaving directory `/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp' + + +Parsed C implicit link information from above output: + link line regex: [^( *|.*[/\])(ld|([^/\]+-)?ld|collect2)[^/\]*( |$)] + ignore line: [Change Dir: /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp] + ignore line: [] + ignore line: [Run Build Command:/usr/bin/make "cmTryCompileExec781799643/fast"] + ignore line: [/usr/bin/make -f CMakeFiles/cmTryCompileExec781799643.dir/build.make CMakeFiles/cmTryCompileExec781799643.dir/build] + ignore line: [make[1]: Entering directory `/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp'] + ignore line: [/usr/bin/cmake -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp/CMakeFiles 1] + ignore line: [Building C object CMakeFiles/cmTryCompileExec781799643.dir/CMakeCCompilerABI.c.o] + ignore line: [/usr/bin/cc -o CMakeFiles/cmTryCompileExec781799643.dir/CMakeCCompilerABI.c.o -c /usr/share/cmake-2.8/Modules/CMakeCCompilerABI.c] + ignore line: [Linking C executable cmTryCompileExec781799643] + ignore line: [/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTryCompileExec781799643.dir/link.txt --verbose=1] + ignore line: [/usr/bin/cc -v CMakeFiles/cmTryCompileExec781799643.dir/CMakeCCompilerABI.c.o -o cmTryCompileExec781799643 -rdynamic ] + ignore line: [Using built-in specs.] + ignore line: [COLLECT_GCC=/usr/bin/cc] + ignore line: [COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/4.8/lto-wrapper] + ignore line: [Target: arm-linux-gnueabihf] + ignore line: [Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.8.4-2ubuntu1~14.04' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --disable-libitm --disable-libquadmath --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-armhf/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-armhf --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-armhf --with-arch-directory=arm --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --enable-multilib --disable-sjlj-exceptions --with-arch=armv7-a --with-fpu=vfpv3-d16 --with-float=hard --with-mode=thumb --disable-werror --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf] + ignore line: [Thread model: posix] + ignore line: [gcc version 4.8.4 (Ubuntu/Linaro 4.8.4-2ubuntu1~14.04) ] + ignore line: [COMPILER_PATH=/usr/lib/gcc/arm-linux-gnueabihf/4.8/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/:/usr/lib/gcc/arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/:/usr/lib/gcc/arm-linux-gnueabihf/] + ignore line: [LIBRARY_PATH=/usr/lib/gcc/arm-linux-gnueabihf/4.8/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../../lib/:/lib/arm-linux-gnueabihf/:/lib/../lib/:/usr/lib/arm-linux-gnueabihf/:/usr/lib/../lib/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../:/lib/:/usr/lib/] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'cmTryCompileExec781799643' '-rdynamic' '-march=armv7-a' '-mfloat-abi=hard' '-mfpu=vfpv3-d16' '-mthumb' '-mtls-dialect=gnu'] + link line: [ /usr/lib/gcc/arm-linux-gnueabihf/4.8/collect2 --sysroot=/ --build-id --eh-frame-hdr -export-dynamic -dynamic-linker /lib/ld-linux-armhf.so.3 -X --hash-style=gnu --as-needed -m armelf_linux_eabi -z relro -o cmTryCompileExec781799643 /usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/crt1.o /usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/crti.o /usr/lib/gcc/arm-linux-gnueabihf/4.8/crtbegin.o -L/usr/lib/gcc/arm-linux-gnueabihf/4.8 -L/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf -L/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../../lib -L/lib/arm-linux-gnueabihf -L/lib/../lib -L/usr/lib/arm-linux-gnueabihf -L/usr/lib/../lib -L/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../.. CMakeFiles/cmTryCompileExec781799643.dir/CMakeCCompilerABI.c.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/arm-linux-gnueabihf/4.8/crtend.o /usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/crtn.o] + arg [/usr/lib/gcc/arm-linux-gnueabihf/4.8/collect2] ==> ignore + arg [--sysroot=/] ==> ignore + arg [--build-id] ==> ignore + arg [--eh-frame-hdr] ==> ignore + arg [-export-dynamic] ==> ignore + arg [-dynamic-linker] ==> ignore + arg [/lib/ld-linux-armhf.so.3] ==> ignore + arg [-X] ==> ignore + arg [--hash-style=gnu] ==> ignore + arg [--as-needed] ==> ignore + arg [-m] ==> ignore + arg [armelf_linux_eabi] ==> ignore + arg [-zrelro] ==> ignore + arg [-o] ==> ignore + arg [cmTryCompileExec781799643] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/crt1.o] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/crti.o] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/4.8/crtbegin.o] ==> ignore + arg [-L/usr/lib/gcc/arm-linux-gnueabihf/4.8] ==> dir [/usr/lib/gcc/arm-linux-gnueabihf/4.8] + arg [-L/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf] ==> dir [/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf] + arg [-L/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../../lib] ==> dir [/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../../lib] + arg [-L/lib/arm-linux-gnueabihf] ==> dir [/lib/arm-linux-gnueabihf] + arg [-L/lib/../lib] ==> dir [/lib/../lib] + arg [-L/usr/lib/arm-linux-gnueabihf] ==> dir [/usr/lib/arm-linux-gnueabihf] + arg [-L/usr/lib/../lib] ==> dir [/usr/lib/../lib] + arg [-L/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../..] ==> dir [/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../..] + arg [CMakeFiles/cmTryCompileExec781799643.dir/CMakeCCompilerABI.c.o] ==> ignore + arg [-lgcc] ==> lib [gcc] + arg [--as-needed] ==> ignore + arg [-lgcc_s] ==> lib [gcc_s] + arg [--no-as-needed] ==> ignore + arg [-lc] ==> lib [c] + arg [-lgcc] ==> lib [gcc] + arg [--as-needed] ==> ignore + arg [-lgcc_s] ==> lib [gcc_s] + arg [--no-as-needed] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/4.8/crtend.o] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/crtn.o] ==> ignore + remove lib [gcc] + remove lib [gcc_s] + remove lib [gcc] + remove lib [gcc_s] + collapse library dir [/usr/lib/gcc/arm-linux-gnueabihf/4.8] ==> [/usr/lib/gcc/arm-linux-gnueabihf/4.8] + collapse library dir [/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf] ==> [/usr/lib/arm-linux-gnueabihf] + collapse library dir [/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../../lib] ==> [/usr/lib] + collapse library dir [/lib/arm-linux-gnueabihf] ==> [/lib/arm-linux-gnueabihf] + collapse library dir [/lib/../lib] ==> [/lib] + collapse library dir [/usr/lib/arm-linux-gnueabihf] ==> [/usr/lib/arm-linux-gnueabihf] + collapse library dir [/usr/lib/../lib] ==> [/usr/lib] + collapse library dir [/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../..] ==> [/usr/lib] + implicit libs: [c] + implicit dirs: [/usr/lib/gcc/arm-linux-gnueabihf/4.8;/usr/lib/arm-linux-gnueabihf;/usr/lib;/lib/arm-linux-gnueabihf;/lib] + implicit fwks: [] + + +Determining if the CXX compiler works passed with the following output: +Change Dir: /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp + +Run Build Command:/usr/bin/make "cmTryCompileExec1028053359/fast" +/usr/bin/make -f CMakeFiles/cmTryCompileExec1028053359.dir/build.make CMakeFiles/cmTryCompileExec1028053359.dir/build +make[1]: Entering directory `/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp' +/usr/bin/cmake -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp/CMakeFiles 1 +Building CXX object CMakeFiles/cmTryCompileExec1028053359.dir/testCXXCompiler.cxx.o +/usr/bin/c++ -o CMakeFiles/cmTryCompileExec1028053359.dir/testCXXCompiler.cxx.o -c /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp/testCXXCompiler.cxx +Linking CXX executable cmTryCompileExec1028053359 +/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTryCompileExec1028053359.dir/link.txt --verbose=1 +/usr/bin/c++ CMakeFiles/cmTryCompileExec1028053359.dir/testCXXCompiler.cxx.o -o cmTryCompileExec1028053359 -rdynamic +make[1]: Leaving directory `/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp' + + +Detecting CXX compiler ABI info compiled with the following output: +Change Dir: /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp + +Run Build Command:/usr/bin/make "cmTryCompileExec3957457156/fast" +/usr/bin/make -f CMakeFiles/cmTryCompileExec3957457156.dir/build.make CMakeFiles/cmTryCompileExec3957457156.dir/build +make[1]: Entering directory `/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp' +/usr/bin/cmake -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp/CMakeFiles 1 +Building CXX object CMakeFiles/cmTryCompileExec3957457156.dir/CMakeCXXCompilerABI.cpp.o +/usr/bin/c++ -o CMakeFiles/cmTryCompileExec3957457156.dir/CMakeCXXCompilerABI.cpp.o -c /usr/share/cmake-2.8/Modules/CMakeCXXCompilerABI.cpp +Linking CXX executable cmTryCompileExec3957457156 +/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTryCompileExec3957457156.dir/link.txt --verbose=1 +/usr/bin/c++ -v CMakeFiles/cmTryCompileExec3957457156.dir/CMakeCXXCompilerABI.cpp.o -o cmTryCompileExec3957457156 -rdynamic +Using built-in specs. +COLLECT_GCC=/usr/bin/c++ +COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/4.8/lto-wrapper +Target: arm-linux-gnueabihf +Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.8.4-2ubuntu1~14.04' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --disable-libitm --disable-libquadmath --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-armhf/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-armhf --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-armhf --with-arch-directory=arm --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --enable-multilib --disable-sjlj-exceptions --with-arch=armv7-a --with-fpu=vfpv3-d16 --with-float=hard --with-mode=thumb --disable-werror --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf +Thread model: posix +gcc version 4.8.4 (Ubuntu/Linaro 4.8.4-2ubuntu1~14.04) +COMPILER_PATH=/usr/lib/gcc/arm-linux-gnueabihf/4.8/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/:/usr/lib/gcc/arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/:/usr/lib/gcc/arm-linux-gnueabihf/ +LIBRARY_PATH=/usr/lib/gcc/arm-linux-gnueabihf/4.8/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../../lib/:/lib/arm-linux-gnueabihf/:/lib/../lib/:/usr/lib/arm-linux-gnueabihf/:/usr/lib/../lib/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../:/lib/:/usr/lib/ +COLLECT_GCC_OPTIONS='-v' '-o' 'cmTryCompileExec3957457156' '-rdynamic' '-shared-libgcc' '-march=armv7-a' '-mfloat-abi=hard' '-mfpu=vfpv3-d16' '-mthumb' '-mtls-dialect=gnu' + /usr/lib/gcc/arm-linux-gnueabihf/4.8/collect2 --sysroot=/ --build-id --eh-frame-hdr -export-dynamic -dynamic-linker /lib/ld-linux-armhf.so.3 -X --hash-style=gnu --as-needed -m armelf_linux_eabi -z relro -o cmTryCompileExec3957457156 /usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/crt1.o /usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/crti.o /usr/lib/gcc/arm-linux-gnueabihf/4.8/crtbegin.o -L/usr/lib/gcc/arm-linux-gnueabihf/4.8 -L/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf -L/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../../lib -L/lib/arm-linux-gnueabihf -L/lib/../lib -L/usr/lib/arm-linux-gnueabihf -L/usr/lib/../lib -L/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../.. CMakeFiles/cmTryCompileExec3957457156.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/arm-linux-gnueabihf/4.8/crtend.o /usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/crtn.o +make[1]: Leaving directory `/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp' + + +Parsed CXX implicit link information from above output: + link line regex: [^( *|.*[/\])(ld|([^/\]+-)?ld|collect2)[^/\]*( |$)] + ignore line: [Change Dir: /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp] + ignore line: [] + ignore line: [Run Build Command:/usr/bin/make "cmTryCompileExec3957457156/fast"] + ignore line: [/usr/bin/make -f CMakeFiles/cmTryCompileExec3957457156.dir/build.make CMakeFiles/cmTryCompileExec3957457156.dir/build] + ignore line: [make[1]: Entering directory `/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp'] + ignore line: [/usr/bin/cmake -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeTmp/CMakeFiles 1] + ignore line: [Building CXX object CMakeFiles/cmTryCompileExec3957457156.dir/CMakeCXXCompilerABI.cpp.o] + ignore line: [/usr/bin/c++ -o CMakeFiles/cmTryCompileExec3957457156.dir/CMakeCXXCompilerABI.cpp.o -c /usr/share/cmake-2.8/Modules/CMakeCXXCompilerABI.cpp] + ignore line: [Linking CXX executable cmTryCompileExec3957457156] + ignore line: [/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTryCompileExec3957457156.dir/link.txt --verbose=1] + ignore line: [/usr/bin/c++ -v CMakeFiles/cmTryCompileExec3957457156.dir/CMakeCXXCompilerABI.cpp.o -o cmTryCompileExec3957457156 -rdynamic ] + ignore line: [Using built-in specs.] + ignore line: [COLLECT_GCC=/usr/bin/c++] + ignore line: [COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/4.8/lto-wrapper] + ignore line: [Target: arm-linux-gnueabihf] + ignore line: [Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.8.4-2ubuntu1~14.04' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --disable-libitm --disable-libquadmath --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-armhf/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-armhf --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-armhf --with-arch-directory=arm --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --enable-multilib --disable-sjlj-exceptions --with-arch=armv7-a --with-fpu=vfpv3-d16 --with-float=hard --with-mode=thumb --disable-werror --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf] + ignore line: [Thread model: posix] + ignore line: [gcc version 4.8.4 (Ubuntu/Linaro 4.8.4-2ubuntu1~14.04) ] + ignore line: [COMPILER_PATH=/usr/lib/gcc/arm-linux-gnueabihf/4.8/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/:/usr/lib/gcc/arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/:/usr/lib/gcc/arm-linux-gnueabihf/] + ignore line: [LIBRARY_PATH=/usr/lib/gcc/arm-linux-gnueabihf/4.8/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../../lib/:/lib/arm-linux-gnueabihf/:/lib/../lib/:/usr/lib/arm-linux-gnueabihf/:/usr/lib/../lib/:/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../:/lib/:/usr/lib/] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'cmTryCompileExec3957457156' '-rdynamic' '-shared-libgcc' '-march=armv7-a' '-mfloat-abi=hard' '-mfpu=vfpv3-d16' '-mthumb' '-mtls-dialect=gnu'] + link line: [ /usr/lib/gcc/arm-linux-gnueabihf/4.8/collect2 --sysroot=/ --build-id --eh-frame-hdr -export-dynamic -dynamic-linker /lib/ld-linux-armhf.so.3 -X --hash-style=gnu --as-needed -m armelf_linux_eabi -z relro -o cmTryCompileExec3957457156 /usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/crt1.o /usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/crti.o /usr/lib/gcc/arm-linux-gnueabihf/4.8/crtbegin.o -L/usr/lib/gcc/arm-linux-gnueabihf/4.8 -L/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf -L/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../../lib -L/lib/arm-linux-gnueabihf -L/lib/../lib -L/usr/lib/arm-linux-gnueabihf -L/usr/lib/../lib -L/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../.. CMakeFiles/cmTryCompileExec3957457156.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/arm-linux-gnueabihf/4.8/crtend.o /usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/crtn.o] + arg [/usr/lib/gcc/arm-linux-gnueabihf/4.8/collect2] ==> ignore + arg [--sysroot=/] ==> ignore + arg [--build-id] ==> ignore + arg [--eh-frame-hdr] ==> ignore + arg [-export-dynamic] ==> ignore + arg [-dynamic-linker] ==> ignore + arg [/lib/ld-linux-armhf.so.3] ==> ignore + arg [-X] ==> ignore + arg [--hash-style=gnu] ==> ignore + arg [--as-needed] ==> ignore + arg [-m] ==> ignore + arg [armelf_linux_eabi] ==> ignore + arg [-zrelro] ==> ignore + arg [-o] ==> ignore + arg [cmTryCompileExec3957457156] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/crt1.o] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/crti.o] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/4.8/crtbegin.o] ==> ignore + arg [-L/usr/lib/gcc/arm-linux-gnueabihf/4.8] ==> dir [/usr/lib/gcc/arm-linux-gnueabihf/4.8] + arg [-L/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf] ==> dir [/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf] + arg [-L/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../../lib] ==> dir [/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../../lib] + arg [-L/lib/arm-linux-gnueabihf] ==> dir [/lib/arm-linux-gnueabihf] + arg [-L/lib/../lib] ==> dir [/lib/../lib] + arg [-L/usr/lib/arm-linux-gnueabihf] ==> dir [/usr/lib/arm-linux-gnueabihf] + arg [-L/usr/lib/../lib] ==> dir [/usr/lib/../lib] + arg [-L/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../..] ==> dir [/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../..] + arg [CMakeFiles/cmTryCompileExec3957457156.dir/CMakeCXXCompilerABI.cpp.o] ==> ignore + arg [-lstdc++] ==> lib [stdc++] + arg [-lm] ==> lib [m] + arg [-lgcc_s] ==> lib [gcc_s] + arg [-lgcc] ==> lib [gcc] + arg [-lc] ==> lib [c] + arg [-lgcc_s] ==> lib [gcc_s] + arg [-lgcc] ==> lib [gcc] + arg [/usr/lib/gcc/arm-linux-gnueabihf/4.8/crtend.o] ==> ignore + arg [/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf/crtn.o] ==> ignore + remove lib [gcc_s] + remove lib [gcc] + remove lib [gcc_s] + remove lib [gcc] + collapse library dir [/usr/lib/gcc/arm-linux-gnueabihf/4.8] ==> [/usr/lib/gcc/arm-linux-gnueabihf/4.8] + collapse library dir [/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../arm-linux-gnueabihf] ==> [/usr/lib/arm-linux-gnueabihf] + collapse library dir [/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../../../lib] ==> [/usr/lib] + collapse library dir [/lib/arm-linux-gnueabihf] ==> [/lib/arm-linux-gnueabihf] + collapse library dir [/lib/../lib] ==> [/lib] + collapse library dir [/usr/lib/arm-linux-gnueabihf] ==> [/usr/lib/arm-linux-gnueabihf] + collapse library dir [/usr/lib/../lib] ==> [/usr/lib] + collapse library dir [/usr/lib/gcc/arm-linux-gnueabihf/4.8/../../..] ==> [/usr/lib] + implicit libs: [stdc++;m;c] + implicit dirs: [/usr/lib/gcc/arm-linux-gnueabihf/4.8;/usr/lib/arm-linux-gnueabihf;/usr/lib;/lib/arm-linux-gnueabihf;/lib] + implicit fwks: [] + + diff --git a/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeRuleHashes.txt b/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeRuleHashes.txt new file mode 100644 index 0000000..f94bc5c --- /dev/null +++ b/external_src/raspicam-0.1.3/build/CMakeFiles/CMakeRuleHashes.txt @@ -0,0 +1,2 @@ +# Hashes of file build rules. +d40b852367b8f17b70ad02dd31dc09d5 CMakeFiles/uninstall diff --git a/external_src/raspicam-0.1.3/build/CMakeFiles/Makefile.cmake b/external_src/raspicam-0.1.3/build/CMakeFiles/Makefile.cmake new file mode 100644 index 0000000..dd33d36 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/CMakeFiles/Makefile.cmake @@ -0,0 +1,87 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# The generator used is: +SET(CMAKE_DEPENDS_GENERATOR "Unix Makefiles") + +# The top level Makefile was generated from the following files: +SET(CMAKE_MAKEFILE_DEPENDS + "CMakeCache.txt" + "../CMakeLists.txt" + "CMakeFiles/2.8.12.2/CMakeCCompiler.cmake" + "CMakeFiles/2.8.12.2/CMakeCXXCompiler.cmake" + "CMakeFiles/2.8.12.2/CMakeSystem.cmake" + "../cmake_uninstall.cmake.in" + "../config.cmake.in" + "../src/CMakeLists.txt" + "../utils/CMakeLists.txt" + "/usr/local/share/OpenCV/OpenCVConfig-version.cmake" + "/usr/local/share/OpenCV/OpenCVConfig.cmake" + "/usr/local/share/OpenCV/OpenCVModules-release.cmake" + "/usr/local/share/OpenCV/OpenCVModules.cmake" + "/usr/share/cmake-2.8/Modules/CMakeCCompiler.cmake.in" + "/usr/share/cmake-2.8/Modules/CMakeCCompilerABI.c" + "/usr/share/cmake-2.8/Modules/CMakeCInformation.cmake" + "/usr/share/cmake-2.8/Modules/CMakeCXXCompiler.cmake.in" + "/usr/share/cmake-2.8/Modules/CMakeCXXCompilerABI.cpp" + "/usr/share/cmake-2.8/Modules/CMakeCXXInformation.cmake" + "/usr/share/cmake-2.8/Modules/CMakeClDeps.cmake" + "/usr/share/cmake-2.8/Modules/CMakeCommonLanguageInclude.cmake" + "/usr/share/cmake-2.8/Modules/CMakeDetermineCCompiler.cmake" + "/usr/share/cmake-2.8/Modules/CMakeDetermineCXXCompiler.cmake" + "/usr/share/cmake-2.8/Modules/CMakeDetermineCompiler.cmake" + "/usr/share/cmake-2.8/Modules/CMakeDetermineCompilerABI.cmake" + "/usr/share/cmake-2.8/Modules/CMakeDetermineCompilerId.cmake" + "/usr/share/cmake-2.8/Modules/CMakeDetermineSystem.cmake" + "/usr/share/cmake-2.8/Modules/CMakeFindBinUtils.cmake" + "/usr/share/cmake-2.8/Modules/CMakeGenericSystem.cmake" + "/usr/share/cmake-2.8/Modules/CMakeParseImplicitLinkInfo.cmake" + "/usr/share/cmake-2.8/Modules/CMakeSystem.cmake.in" + "/usr/share/cmake-2.8/Modules/CMakeSystemSpecificInformation.cmake" + "/usr/share/cmake-2.8/Modules/CMakeTestCCompiler.cmake" + "/usr/share/cmake-2.8/Modules/CMakeTestCXXCompiler.cmake" + "/usr/share/cmake-2.8/Modules/CMakeTestCompilerCommon.cmake" + "/usr/share/cmake-2.8/Modules/CMakeUnixFindMake.cmake" + "/usr/share/cmake-2.8/Modules/Compiler/GNU-C.cmake" + "/usr/share/cmake-2.8/Modules/Compiler/GNU-CXX.cmake" + "/usr/share/cmake-2.8/Modules/Compiler/GNU.cmake" + "/usr/share/cmake-2.8/Modules/MultiArchCross.cmake" + "/usr/share/cmake-2.8/Modules/Platform/Linux-CXX.cmake" + "/usr/share/cmake-2.8/Modules/Platform/Linux-GNU-C.cmake" + "/usr/share/cmake-2.8/Modules/Platform/Linux-GNU-CXX.cmake" + "/usr/share/cmake-2.8/Modules/Platform/Linux-GNU.cmake" + "/usr/share/cmake-2.8/Modules/Platform/Linux.cmake" + "/usr/share/cmake-2.8/Modules/Platform/UnixPaths.cmake" + ) + +# The corresponding makefile is: +SET(CMAKE_MAKEFILE_OUTPUTS + "Makefile" + "CMakeFiles/cmake.check_cache" + ) + +# Byproducts of CMake generate step: +SET(CMAKE_MAKEFILE_PRODUCTS + "CMakeFiles/2.8.12.2/CMakeSystem.cmake" + "CMakeFiles/2.8.12.2/CMakeCCompiler.cmake" + "CMakeFiles/2.8.12.2/CMakeCXXCompiler.cmake" + "CMakeFiles/2.8.12.2/CMakeCCompiler.cmake" + "CMakeFiles/2.8.12.2/CMakeCXXCompiler.cmake" + "cmake_uninstall.cmake" + "Findraspicam.cmake" + "raspicamConfig.cmake" + "CMakeFiles/CMakeDirectoryInformation.cmake" + "src/CMakeFiles/CMakeDirectoryInformation.cmake" + "utils/CMakeFiles/CMakeDirectoryInformation.cmake" + ) + +# Dependency information for all targets: +SET(CMAKE_DEPEND_INFO_FILES + "CMakeFiles/uninstall.dir/DependInfo.cmake" + "src/CMakeFiles/raspicam.dir/DependInfo.cmake" + "src/CMakeFiles/raspicam_cv.dir/DependInfo.cmake" + "utils/CMakeFiles/raspicam_cv_still_test.dir/DependInfo.cmake" + "utils/CMakeFiles/raspicam_cv_test.dir/DependInfo.cmake" + "utils/CMakeFiles/raspicam_still_test.dir/DependInfo.cmake" + "utils/CMakeFiles/raspicam_test.dir/DependInfo.cmake" + ) diff --git a/external_src/raspicam-0.1.3/build/CMakeFiles/Makefile2 b/external_src/raspicam-0.1.3/build/CMakeFiles/Makefile2 new file mode 100644 index 0000000..8863e1c --- /dev/null +++ b/external_src/raspicam-0.1.3/build/CMakeFiles/Makefile2 @@ -0,0 +1,345 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +# The main recursive all target +all: +.PHONY : all + +# The main recursive preinstall target +preinstall: +.PHONY : preinstall + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E remove -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build + +#============================================================================= +# Target rules for target CMakeFiles/uninstall.dir + +# All Build rule for target. +CMakeFiles/uninstall.dir/all: + $(MAKE) -f CMakeFiles/uninstall.dir/build.make CMakeFiles/uninstall.dir/depend + $(MAKE) -f CMakeFiles/uninstall.dir/build.make CMakeFiles/uninstall.dir/build + $(CMAKE_COMMAND) -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles + @echo "Built target uninstall" +.PHONY : CMakeFiles/uninstall.dir/all + +# Build rule for subdir invocation for target. +CMakeFiles/uninstall.dir/rule: cmake_check_build_system + $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 0 + $(MAKE) -f CMakeFiles/Makefile2 CMakeFiles/uninstall.dir/all + $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 0 +.PHONY : CMakeFiles/uninstall.dir/rule + +# Convenience name for target. +uninstall: CMakeFiles/uninstall.dir/rule +.PHONY : uninstall + +# clean rule for target. +CMakeFiles/uninstall.dir/clean: + $(MAKE) -f CMakeFiles/uninstall.dir/build.make CMakeFiles/uninstall.dir/clean +.PHONY : CMakeFiles/uninstall.dir/clean + +# clean rule for target. +clean: CMakeFiles/uninstall.dir/clean +.PHONY : clean + +#============================================================================= +# Directory level rules for directory src + +# Convenience name for "all" pass in the directory. +src/all: src/CMakeFiles/raspicam.dir/all +src/all: src/CMakeFiles/raspicam_cv.dir/all +.PHONY : src/all + +# Convenience name for "clean" pass in the directory. +src/clean: src/CMakeFiles/raspicam.dir/clean +src/clean: src/CMakeFiles/raspicam_cv.dir/clean +.PHONY : src/clean + +# Convenience name for "preinstall" pass in the directory. +src/preinstall: +.PHONY : src/preinstall + +#============================================================================= +# Target rules for target src/CMakeFiles/raspicam.dir + +# All Build rule for target. +src/CMakeFiles/raspicam.dir/all: + $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/depend + $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/build + $(CMAKE_COMMAND) -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 1 2 3 4 5 + @echo "Built target raspicam" +.PHONY : src/CMakeFiles/raspicam.dir/all + +# Include target in all. +all: src/CMakeFiles/raspicam.dir/all +.PHONY : all + +# Build rule for subdir invocation for target. +src/CMakeFiles/raspicam.dir/rule: cmake_check_build_system + $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 5 + $(MAKE) -f CMakeFiles/Makefile2 src/CMakeFiles/raspicam.dir/all + $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 0 +.PHONY : src/CMakeFiles/raspicam.dir/rule + +# Convenience name for target. +raspicam: src/CMakeFiles/raspicam.dir/rule +.PHONY : raspicam + +# clean rule for target. +src/CMakeFiles/raspicam.dir/clean: + $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/clean +.PHONY : src/CMakeFiles/raspicam.dir/clean + +# clean rule for target. +clean: src/CMakeFiles/raspicam.dir/clean +.PHONY : clean + +#============================================================================= +# Target rules for target src/CMakeFiles/raspicam_cv.dir + +# All Build rule for target. +src/CMakeFiles/raspicam_cv.dir/all: + $(MAKE) -f src/CMakeFiles/raspicam_cv.dir/build.make src/CMakeFiles/raspicam_cv.dir/depend + $(MAKE) -f src/CMakeFiles/raspicam_cv.dir/build.make src/CMakeFiles/raspicam_cv.dir/build + $(CMAKE_COMMAND) -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 6 7 + @echo "Built target raspicam_cv" +.PHONY : src/CMakeFiles/raspicam_cv.dir/all + +# Include target in all. +all: src/CMakeFiles/raspicam_cv.dir/all +.PHONY : all + +# Build rule for subdir invocation for target. +src/CMakeFiles/raspicam_cv.dir/rule: cmake_check_build_system + $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 2 + $(MAKE) -f CMakeFiles/Makefile2 src/CMakeFiles/raspicam_cv.dir/all + $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 0 +.PHONY : src/CMakeFiles/raspicam_cv.dir/rule + +# Convenience name for target. +raspicam_cv: src/CMakeFiles/raspicam_cv.dir/rule +.PHONY : raspicam_cv + +# clean rule for target. +src/CMakeFiles/raspicam_cv.dir/clean: + $(MAKE) -f src/CMakeFiles/raspicam_cv.dir/build.make src/CMakeFiles/raspicam_cv.dir/clean +.PHONY : src/CMakeFiles/raspicam_cv.dir/clean + +# clean rule for target. +clean: src/CMakeFiles/raspicam_cv.dir/clean +.PHONY : clean + +#============================================================================= +# Directory level rules for directory utils + +# Convenience name for "all" pass in the directory. +utils/all: utils/CMakeFiles/raspicam_cv_still_test.dir/all +utils/all: utils/CMakeFiles/raspicam_cv_test.dir/all +utils/all: utils/CMakeFiles/raspicam_still_test.dir/all +utils/all: utils/CMakeFiles/raspicam_test.dir/all +.PHONY : utils/all + +# Convenience name for "clean" pass in the directory. +utils/clean: utils/CMakeFiles/raspicam_cv_still_test.dir/clean +utils/clean: utils/CMakeFiles/raspicam_cv_test.dir/clean +utils/clean: utils/CMakeFiles/raspicam_still_test.dir/clean +utils/clean: utils/CMakeFiles/raspicam_test.dir/clean +.PHONY : utils/clean + +# Convenience name for "preinstall" pass in the directory. +utils/preinstall: +.PHONY : utils/preinstall + +#============================================================================= +# Target rules for target utils/CMakeFiles/raspicam_cv_still_test.dir + +# All Build rule for target. +utils/CMakeFiles/raspicam_cv_still_test.dir/all: src/CMakeFiles/raspicam_cv.dir/all +utils/CMakeFiles/raspicam_cv_still_test.dir/all: src/CMakeFiles/raspicam.dir/all + $(MAKE) -f utils/CMakeFiles/raspicam_cv_still_test.dir/build.make utils/CMakeFiles/raspicam_cv_still_test.dir/depend + $(MAKE) -f utils/CMakeFiles/raspicam_cv_still_test.dir/build.make utils/CMakeFiles/raspicam_cv_still_test.dir/build + $(CMAKE_COMMAND) -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 8 + @echo "Built target raspicam_cv_still_test" +.PHONY : utils/CMakeFiles/raspicam_cv_still_test.dir/all + +# Include target in all. +all: utils/CMakeFiles/raspicam_cv_still_test.dir/all +.PHONY : all + +# Build rule for subdir invocation for target. +utils/CMakeFiles/raspicam_cv_still_test.dir/rule: cmake_check_build_system + $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 8 + $(MAKE) -f CMakeFiles/Makefile2 utils/CMakeFiles/raspicam_cv_still_test.dir/all + $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 0 +.PHONY : utils/CMakeFiles/raspicam_cv_still_test.dir/rule + +# Convenience name for target. +raspicam_cv_still_test: utils/CMakeFiles/raspicam_cv_still_test.dir/rule +.PHONY : raspicam_cv_still_test + +# clean rule for target. +utils/CMakeFiles/raspicam_cv_still_test.dir/clean: + $(MAKE) -f utils/CMakeFiles/raspicam_cv_still_test.dir/build.make utils/CMakeFiles/raspicam_cv_still_test.dir/clean +.PHONY : utils/CMakeFiles/raspicam_cv_still_test.dir/clean + +# clean rule for target. +clean: utils/CMakeFiles/raspicam_cv_still_test.dir/clean +.PHONY : clean + +#============================================================================= +# Target rules for target utils/CMakeFiles/raspicam_cv_test.dir + +# All Build rule for target. +utils/CMakeFiles/raspicam_cv_test.dir/all: src/CMakeFiles/raspicam_cv.dir/all +utils/CMakeFiles/raspicam_cv_test.dir/all: src/CMakeFiles/raspicam.dir/all + $(MAKE) -f utils/CMakeFiles/raspicam_cv_test.dir/build.make utils/CMakeFiles/raspicam_cv_test.dir/depend + $(MAKE) -f utils/CMakeFiles/raspicam_cv_test.dir/build.make utils/CMakeFiles/raspicam_cv_test.dir/build + $(CMAKE_COMMAND) -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 9 + @echo "Built target raspicam_cv_test" +.PHONY : utils/CMakeFiles/raspicam_cv_test.dir/all + +# Include target in all. +all: utils/CMakeFiles/raspicam_cv_test.dir/all +.PHONY : all + +# Build rule for subdir invocation for target. +utils/CMakeFiles/raspicam_cv_test.dir/rule: cmake_check_build_system + $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 8 + $(MAKE) -f CMakeFiles/Makefile2 utils/CMakeFiles/raspicam_cv_test.dir/all + $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 0 +.PHONY : utils/CMakeFiles/raspicam_cv_test.dir/rule + +# Convenience name for target. +raspicam_cv_test: utils/CMakeFiles/raspicam_cv_test.dir/rule +.PHONY : raspicam_cv_test + +# clean rule for target. +utils/CMakeFiles/raspicam_cv_test.dir/clean: + $(MAKE) -f utils/CMakeFiles/raspicam_cv_test.dir/build.make utils/CMakeFiles/raspicam_cv_test.dir/clean +.PHONY : utils/CMakeFiles/raspicam_cv_test.dir/clean + +# clean rule for target. +clean: utils/CMakeFiles/raspicam_cv_test.dir/clean +.PHONY : clean + +#============================================================================= +# Target rules for target utils/CMakeFiles/raspicam_still_test.dir + +# All Build rule for target. +utils/CMakeFiles/raspicam_still_test.dir/all: src/CMakeFiles/raspicam.dir/all + $(MAKE) -f utils/CMakeFiles/raspicam_still_test.dir/build.make utils/CMakeFiles/raspicam_still_test.dir/depend + $(MAKE) -f utils/CMakeFiles/raspicam_still_test.dir/build.make utils/CMakeFiles/raspicam_still_test.dir/build + $(CMAKE_COMMAND) -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 10 + @echo "Built target raspicam_still_test" +.PHONY : utils/CMakeFiles/raspicam_still_test.dir/all + +# Include target in all. +all: utils/CMakeFiles/raspicam_still_test.dir/all +.PHONY : all + +# Build rule for subdir invocation for target. +utils/CMakeFiles/raspicam_still_test.dir/rule: cmake_check_build_system + $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 6 + $(MAKE) -f CMakeFiles/Makefile2 utils/CMakeFiles/raspicam_still_test.dir/all + $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 0 +.PHONY : utils/CMakeFiles/raspicam_still_test.dir/rule + +# Convenience name for target. +raspicam_still_test: utils/CMakeFiles/raspicam_still_test.dir/rule +.PHONY : raspicam_still_test + +# clean rule for target. +utils/CMakeFiles/raspicam_still_test.dir/clean: + $(MAKE) -f utils/CMakeFiles/raspicam_still_test.dir/build.make utils/CMakeFiles/raspicam_still_test.dir/clean +.PHONY : utils/CMakeFiles/raspicam_still_test.dir/clean + +# clean rule for target. +clean: utils/CMakeFiles/raspicam_still_test.dir/clean +.PHONY : clean + +#============================================================================= +# Target rules for target utils/CMakeFiles/raspicam_test.dir + +# All Build rule for target. +utils/CMakeFiles/raspicam_test.dir/all: src/CMakeFiles/raspicam.dir/all + $(MAKE) -f utils/CMakeFiles/raspicam_test.dir/build.make utils/CMakeFiles/raspicam_test.dir/depend + $(MAKE) -f utils/CMakeFiles/raspicam_test.dir/build.make utils/CMakeFiles/raspicam_test.dir/build + $(CMAKE_COMMAND) -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 11 + @echo "Built target raspicam_test" +.PHONY : utils/CMakeFiles/raspicam_test.dir/all + +# Include target in all. +all: utils/CMakeFiles/raspicam_test.dir/all +.PHONY : all + +# Build rule for subdir invocation for target. +utils/CMakeFiles/raspicam_test.dir/rule: cmake_check_build_system + $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 6 + $(MAKE) -f CMakeFiles/Makefile2 utils/CMakeFiles/raspicam_test.dir/all + $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 0 +.PHONY : utils/CMakeFiles/raspicam_test.dir/rule + +# Convenience name for target. +raspicam_test: utils/CMakeFiles/raspicam_test.dir/rule +.PHONY : raspicam_test + +# clean rule for target. +utils/CMakeFiles/raspicam_test.dir/clean: + $(MAKE) -f utils/CMakeFiles/raspicam_test.dir/build.make utils/CMakeFiles/raspicam_test.dir/clean +.PHONY : utils/CMakeFiles/raspicam_test.dir/clean + +# clean rule for target. +clean: utils/CMakeFiles/raspicam_test.dir/clean +.PHONY : clean + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/external_src/raspicam-0.1.3/build/CMakeFiles/TargetDirectories.txt b/external_src/raspicam-0.1.3/build/CMakeFiles/TargetDirectories.txt new file mode 100644 index 0000000..824a262 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/CMakeFiles/TargetDirectories.txt @@ -0,0 +1,7 @@ +/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir +/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir +/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir +/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir +/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir +/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir +/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/uninstall.dir diff --git a/external_src/raspicam-0.1.3/build/CMakeFiles/cmake.check_cache b/external_src/raspicam-0.1.3/build/CMakeFiles/cmake.check_cache new file mode 100644 index 0000000..3dccd73 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/CMakeFiles/cmake.check_cache @@ -0,0 +1 @@ +# This file is generated by cmake for dependency checking of the CMakeCache.txt file diff --git a/external_src/raspicam-0.1.3/build/CMakeFiles/progress.marks b/external_src/raspicam-0.1.3/build/CMakeFiles/progress.marks new file mode 100644 index 0000000..b4de394 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/CMakeFiles/progress.marks @@ -0,0 +1 @@ +11 diff --git a/external_src/raspicam-0.1.3/build/CMakeFiles/uninstall.dir/DependInfo.cmake b/external_src/raspicam-0.1.3/build/CMakeFiles/uninstall.dir/DependInfo.cmake new file mode 100644 index 0000000..604a15b --- /dev/null +++ b/external_src/raspicam-0.1.3/build/CMakeFiles/uninstall.dir/DependInfo.cmake @@ -0,0 +1,20 @@ +# The set of languages for which implicit dependencies are needed: +SET(CMAKE_DEPENDS_LANGUAGES + ) +# The set of files for implicit dependencies of each language: + +# Targets to which this target links. +SET(CMAKE_TARGET_LINKED_INFO_FILES + ) + +# The include file search paths: +SET(CMAKE_C_TARGET_INCLUDE_PATH + "../dependencies" + "../dependencies/mmal" + "../dependencies/vcos" + "/usr/local/include/opencv" + "/usr/local/include" + ) +SET(CMAKE_CXX_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_Fortran_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_ASM_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) diff --git a/external_src/raspicam-0.1.3/build/CMakeFiles/uninstall.dir/build.make b/external_src/raspicam-0.1.3/build/CMakeFiles/uninstall.dir/build.make new file mode 100644 index 0000000..0eb233a --- /dev/null +++ b/external_src/raspicam-0.1.3/build/CMakeFiles/uninstall.dir/build.make @@ -0,0 +1,66 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E remove -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build + +# Utility rule file for uninstall. + +# Include the progress variables for this target. +include CMakeFiles/uninstall.dir/progress.make + +CMakeFiles/uninstall: + /usr/bin/cmake -P /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/cmake_uninstall.cmake + +uninstall: CMakeFiles/uninstall +uninstall: CMakeFiles/uninstall.dir/build.make +.PHONY : uninstall + +# Rule to build all files generated by this target. +CMakeFiles/uninstall.dir/build: uninstall +.PHONY : CMakeFiles/uninstall.dir/build + +CMakeFiles/uninstall.dir/clean: + $(CMAKE_COMMAND) -P CMakeFiles/uninstall.dir/cmake_clean.cmake +.PHONY : CMakeFiles/uninstall.dir/clean + +CMakeFiles/uninstall.dir/depend: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /home/ubuntu/Nomad/external_src/raspicam-0.1.3 /home/ubuntu/Nomad/external_src/raspicam-0.1.3 /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/uninstall.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : CMakeFiles/uninstall.dir/depend + diff --git a/external_src/raspicam-0.1.3/build/CMakeFiles/uninstall.dir/cmake_clean.cmake b/external_src/raspicam-0.1.3/build/CMakeFiles/uninstall.dir/cmake_clean.cmake new file mode 100644 index 0000000..828e2a2 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/CMakeFiles/uninstall.dir/cmake_clean.cmake @@ -0,0 +1,8 @@ +FILE(REMOVE_RECURSE + "CMakeFiles/uninstall" +) + +# Per-language clean rules from dependency scanning. +FOREACH(lang) + INCLUDE(CMakeFiles/uninstall.dir/cmake_clean_${lang}.cmake OPTIONAL) +ENDFOREACH(lang) diff --git a/external_src/raspicam-0.1.3/build/CMakeFiles/uninstall.dir/progress.make b/external_src/raspicam-0.1.3/build/CMakeFiles/uninstall.dir/progress.make new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/CMakeFiles/uninstall.dir/progress.make @@ -0,0 +1 @@ + diff --git a/external_src/raspicam-0.1.3/build/Findraspicam.cmake b/external_src/raspicam-0.1.3/build/Findraspicam.cmake new file mode 100644 index 0000000..539e008 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/Findraspicam.cmake @@ -0,0 +1,34 @@ +# =================================================================================== +# raspicam CMake configuration file +# +# ** File generated automatically, do not modify ** +# +# Usage from an external project: +# In your CMakeLists.txt, add these lines: +# +# FIND_PACKAGE(raspicam REQUIRED ) +# TARGET_LINK_LIBRARIES(MY_TARGET_NAME ) +# +# This file will define the following variables: +# - raspicam_LIBS : The list of libraries to links against. +# - raspicam_LIB_DIR : The directory where lib files are. Calling LINK_DIRECTORIES +# with this path is NOT needed. +# - raspicam_VERSION : The version of this PROJECT_NAME build. Example: "1.2.0" +# - raspicam_VERSION_MAJOR : Major version part of VERSION. Example: "1" +# - raspicam_VERSION_MINOR : Minor version part of VERSION. Example: "2" +# - raspicam_VERSION_PATCH : Patch version part of VERSION. Example: "0" +# +# =================================================================================== +INCLUDE_DIRECTORIES(;/usr/local/include) +LINK_DIRECTORIES("/usr/local/lib") + +SET(raspicam_LIBS /opt/vc/lib/libmmal_core.so;/opt/vc/lib/libmmal_util.so;/opt/vc/lib/libmmal.so raspicam) +SET(raspicam_FOUND "YES") + +SET(raspicam_CV_FOUND "YES") +SET(raspicam_CV_LIBS /opt/vc/lib/libmmal_core.so;/opt/vc/lib/libmmal_util.so;/opt/vc/lib/libmmal.so raspicam opencv_videostab;opencv_videoio;opencv_video;opencv_superres;opencv_stitching;opencv_shape;opencv_photo;opencv_objdetect;opencv_ml;opencv_imgproc;opencv_imgcodecs;opencv_highgui;opencv_hal;opencv_flann;opencv_features2d;opencv_core;opencv_calib3d raspicam_cv) + +SET(raspicam_VERSION 0.1.2) +SET(raspicam_VERSION_MAJOR 0) +SET(raspicam_VERSION_MINOR 1) +SET(raspicam_VERSION_PATCH 2) diff --git a/external_src/raspicam-0.1.3/build/Makefile b/external_src/raspicam-0.1.3/build/Makefile new file mode 100644 index 0000000..f175eb8 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/Makefile @@ -0,0 +1,265 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E remove -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running interactive CMake command-line interface..." + /usr/bin/cmake -i . +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache +.PHONY : edit_cache/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /usr/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /usr/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: install/local +.PHONY : install/local/fast + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: install/strip +.PHONY : install/strip/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\" \"main\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components +.PHONY : list_install_components/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /usr/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache +.PHONY : rebuild_cache/fast + +# The main all target +all: cmake_check_build_system + $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles/progress.marks + $(MAKE) -f CMakeFiles/Makefile2 all + $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + $(MAKE) -f CMakeFiles/Makefile2 clean +.PHONY : clean + +# The main clean target +clean/fast: clean +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + $(MAKE) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + $(MAKE) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +#============================================================================= +# Target rules for targets named uninstall + +# Build rule for target. +uninstall: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 uninstall +.PHONY : uninstall + +# fast build rule for target. +uninstall/fast: + $(MAKE) -f CMakeFiles/uninstall.dir/build.make CMakeFiles/uninstall.dir/build +.PHONY : uninstall/fast + +#============================================================================= +# Target rules for targets named raspicam + +# Build rule for target. +raspicam: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 raspicam +.PHONY : raspicam + +# fast build rule for target. +raspicam/fast: + $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/build +.PHONY : raspicam/fast + +#============================================================================= +# Target rules for targets named raspicam_cv + +# Build rule for target. +raspicam_cv: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 raspicam_cv +.PHONY : raspicam_cv + +# fast build rule for target. +raspicam_cv/fast: + $(MAKE) -f src/CMakeFiles/raspicam_cv.dir/build.make src/CMakeFiles/raspicam_cv.dir/build +.PHONY : raspicam_cv/fast + +#============================================================================= +# Target rules for targets named raspicam_cv_still_test + +# Build rule for target. +raspicam_cv_still_test: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 raspicam_cv_still_test +.PHONY : raspicam_cv_still_test + +# fast build rule for target. +raspicam_cv_still_test/fast: + $(MAKE) -f utils/CMakeFiles/raspicam_cv_still_test.dir/build.make utils/CMakeFiles/raspicam_cv_still_test.dir/build +.PHONY : raspicam_cv_still_test/fast + +#============================================================================= +# Target rules for targets named raspicam_cv_test + +# Build rule for target. +raspicam_cv_test: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 raspicam_cv_test +.PHONY : raspicam_cv_test + +# fast build rule for target. +raspicam_cv_test/fast: + $(MAKE) -f utils/CMakeFiles/raspicam_cv_test.dir/build.make utils/CMakeFiles/raspicam_cv_test.dir/build +.PHONY : raspicam_cv_test/fast + +#============================================================================= +# Target rules for targets named raspicam_still_test + +# Build rule for target. +raspicam_still_test: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 raspicam_still_test +.PHONY : raspicam_still_test + +# fast build rule for target. +raspicam_still_test/fast: + $(MAKE) -f utils/CMakeFiles/raspicam_still_test.dir/build.make utils/CMakeFiles/raspicam_still_test.dir/build +.PHONY : raspicam_still_test/fast + +#============================================================================= +# Target rules for targets named raspicam_test + +# Build rule for target. +raspicam_test: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 raspicam_test +.PHONY : raspicam_test + +# fast build rule for target. +raspicam_test/fast: + $(MAKE) -f utils/CMakeFiles/raspicam_test.dir/build.make utils/CMakeFiles/raspicam_test.dir/build +.PHONY : raspicam_test/fast + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... install" + @echo "... install/local" + @echo "... install/strip" + @echo "... list_install_components" + @echo "... rebuild_cache" + @echo "... uninstall" + @echo "... raspicam" + @echo "... raspicam_cv" + @echo "... raspicam_cv_still_test" + @echo "... raspicam_cv_test" + @echo "... raspicam_still_test" + @echo "... raspicam_test" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/external_src/raspicam-0.1.3/build/cmake_install.cmake b/external_src/raspicam-0.1.3/build/cmake_install.cmake new file mode 100644 index 0000000..cacc597 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/cmake_install.cmake @@ -0,0 +1,59 @@ +# Install script for directory: /home/ubuntu/Nomad/external_src/raspicam-0.1.3 + +# Set the install prefix +IF(NOT DEFINED CMAKE_INSTALL_PREFIX) + SET(CMAKE_INSTALL_PREFIX "/usr/local") +ENDIF(NOT DEFINED CMAKE_INSTALL_PREFIX) +STRING(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +IF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + IF(BUILD_TYPE) + STRING(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + ELSE(BUILD_TYPE) + SET(CMAKE_INSTALL_CONFIG_NAME "Release") + ENDIF(BUILD_TYPE) + MESSAGE(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +ENDIF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + +# Set the component getting installed. +IF(NOT CMAKE_INSTALL_COMPONENT) + IF(COMPONENT) + MESSAGE(STATUS "Install component: \"${COMPONENT}\"") + SET(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + ELSE(COMPONENT) + SET(CMAKE_INSTALL_COMPONENT) + ENDIF(COMPONENT) +ENDIF(NOT CMAKE_INSTALL_COMPONENT) + +# Install shared libraries without execute permission? +IF(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) + SET(CMAKE_INSTALL_SO_NO_EXE "1") +ENDIF(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) + +IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified") + FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/cmake" TYPE FILE FILES "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/Findraspicam.cmake") +ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified") + +IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified") + FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/cmake" TYPE FILE FILES "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/raspicamConfig.cmake") +ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified") + +IF(NOT CMAKE_INSTALL_LOCAL_ONLY) + # Include the install script for each subdirectory. + INCLUDE("/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/cmake_install.cmake") + INCLUDE("/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils/cmake_install.cmake") + +ENDIF(NOT CMAKE_INSTALL_LOCAL_ONLY) + +IF(CMAKE_INSTALL_COMPONENT) + SET(CMAKE_INSTALL_MANIFEST "install_manifest_${CMAKE_INSTALL_COMPONENT}.txt") +ELSE(CMAKE_INSTALL_COMPONENT) + SET(CMAKE_INSTALL_MANIFEST "install_manifest.txt") +ENDIF(CMAKE_INSTALL_COMPONENT) + +FILE(WRITE "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/${CMAKE_INSTALL_MANIFEST}" "") +FOREACH(file ${CMAKE_INSTALL_MANIFEST_FILES}) + FILE(APPEND "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/${CMAKE_INSTALL_MANIFEST}" "${file}\n") +ENDFOREACH(file) diff --git a/external_src/raspicam-0.1.3/build/cmake_uninstall.cmake b/external_src/raspicam-0.1.3/build/cmake_uninstall.cmake new file mode 100644 index 0000000..46a149b --- /dev/null +++ b/external_src/raspicam-0.1.3/build/cmake_uninstall.cmake @@ -0,0 +1,28 @@ +# ----------------------------------------------- +# File that provides "make uninstall" target +# We use the file 'install_manifest.txt' +# ----------------------------------------------- +IF(NOT EXISTS "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/install_manifest.txt") + MESSAGE(FATAL_ERROR "Cannot find install manifest: \"/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/install_manifest.txt\"") +ENDIF(NOT EXISTS "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/install_manifest.txt") + +FILE(READ "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/install_manifest.txt" files) +STRING(REGEX REPLACE "\n" ";" files "${files}") +FOREACH(file ${files}) + MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") +# IF(EXISTS "$ENV{DESTDIR}${file}") +# EXEC_PROGRAM( +# "/usr/bin/cmake" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" +# OUTPUT_VARIABLE rm_out +# RETURN_VALUE rm_retval +# ) + EXECUTE_PROCESS(COMMAND rm $ENV{DESTDIR}${file}) +# IF(NOT "${rm_retval}" STREQUAL 0) +# MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") +# ENDIF(NOT "${rm_retval}" STREQUAL 0) +# ELSE(EXISTS "$ENV{DESTDIR}${file}") +# MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") +# ENDIF(EXISTS "$ENV{DESTDIR}${file}") +ENDFOREACH(file) + + diff --git a/external_src/raspicam-0.1.3/build/raspicamConfig.cmake b/external_src/raspicam-0.1.3/build/raspicamConfig.cmake new file mode 100644 index 0000000..539e008 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/raspicamConfig.cmake @@ -0,0 +1,34 @@ +# =================================================================================== +# raspicam CMake configuration file +# +# ** File generated automatically, do not modify ** +# +# Usage from an external project: +# In your CMakeLists.txt, add these lines: +# +# FIND_PACKAGE(raspicam REQUIRED ) +# TARGET_LINK_LIBRARIES(MY_TARGET_NAME ) +# +# This file will define the following variables: +# - raspicam_LIBS : The list of libraries to links against. +# - raspicam_LIB_DIR : The directory where lib files are. Calling LINK_DIRECTORIES +# with this path is NOT needed. +# - raspicam_VERSION : The version of this PROJECT_NAME build. Example: "1.2.0" +# - raspicam_VERSION_MAJOR : Major version part of VERSION. Example: "1" +# - raspicam_VERSION_MINOR : Minor version part of VERSION. Example: "2" +# - raspicam_VERSION_PATCH : Patch version part of VERSION. Example: "0" +# +# =================================================================================== +INCLUDE_DIRECTORIES(;/usr/local/include) +LINK_DIRECTORIES("/usr/local/lib") + +SET(raspicam_LIBS /opt/vc/lib/libmmal_core.so;/opt/vc/lib/libmmal_util.so;/opt/vc/lib/libmmal.so raspicam) +SET(raspicam_FOUND "YES") + +SET(raspicam_CV_FOUND "YES") +SET(raspicam_CV_LIBS /opt/vc/lib/libmmal_core.so;/opt/vc/lib/libmmal_util.so;/opt/vc/lib/libmmal.so raspicam opencv_videostab;opencv_videoio;opencv_video;opencv_superres;opencv_stitching;opencv_shape;opencv_photo;opencv_objdetect;opencv_ml;opencv_imgproc;opencv_imgcodecs;opencv_highgui;opencv_hal;opencv_flann;opencv_features2d;opencv_core;opencv_calib3d raspicam_cv) + +SET(raspicam_VERSION 0.1.2) +SET(raspicam_VERSION_MAJOR 0) +SET(raspicam_VERSION_MINOR 1) +SET(raspicam_VERSION_PATCH 2) diff --git a/external_src/raspicam-0.1.3/build/src/CMakeFiles/CMakeDirectoryInformation.cmake b/external_src/raspicam-0.1.3/build/src/CMakeFiles/CMakeDirectoryInformation.cmake new file mode 100644 index 0000000..24120d7 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/src/CMakeFiles/CMakeDirectoryInformation.cmake @@ -0,0 +1,16 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Relative path conversion top directories. +SET(CMAKE_RELATIVE_PATH_TOP_SOURCE "/home/ubuntu/Nomad/external_src/raspicam-0.1.3") +SET(CMAKE_RELATIVE_PATH_TOP_BINARY "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build") + +# Force unix paths in dependencies. +SET(CMAKE_FORCE_UNIX_PATHS 1) + + +# The C and CXX include file regular expressions for this directory. +SET(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$") +SET(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$") +SET(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN}) +SET(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN}) diff --git a/external_src/raspicam-0.1.3/build/src/CMakeFiles/progress.marks b/external_src/raspicam-0.1.3/build/src/CMakeFiles/progress.marks new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/src/CMakeFiles/progress.marks @@ -0,0 +1 @@ +7 diff --git a/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/DependInfo.cmake b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/DependInfo.cmake new file mode 100644 index 0000000..3ffd2bc --- /dev/null +++ b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/DependInfo.cmake @@ -0,0 +1,38 @@ +# The set of languages for which implicit dependencies are needed: +SET(CMAKE_DEPENDS_LANGUAGES + "CXX" + ) +# The set of files for implicit dependencies of each language: +SET(CMAKE_DEPENDS_CHECK_CXX + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/private/private_impl.cpp" "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/private/private_impl.cpp.o" + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/private/threadcondition.cpp" "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/private/threadcondition.cpp.o" + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/private_still/private_still_impl.cpp" "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.o" + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicam.cpp" "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/raspicam.cpp.o" + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicam_still.cpp" "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/raspicam_still.cpp.o" + ) +SET(CMAKE_CXX_COMPILER_ID "GNU") + +# Pairs of files generated by the same build rule. +SET(CMAKE_MULTIPLE_OUTPUT_PAIRS + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/libraspicam.so" "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/libraspicam.so.0.1.2" + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/libraspicam.so.0.1" "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/libraspicam.so.0.1.2" + ) + + +# Targets to which this target links. +SET(CMAKE_TARGET_LINKED_INFO_FILES + ) + +# The include file search paths: +SET(CMAKE_C_TARGET_INCLUDE_PATH + "../dependencies" + "../dependencies/mmal" + "../dependencies/vcos" + "/usr/local/include/opencv" + "/usr/local/include" + "../src/." + "src" + ) +SET(CMAKE_CXX_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_Fortran_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_ASM_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) diff --git a/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/build.make b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/build.make new file mode 100644 index 0000000..510a80c --- /dev/null +++ b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/build.make @@ -0,0 +1,214 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E remove -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build + +# Include any dependencies generated for this target. +include src/CMakeFiles/raspicam.dir/depend.make + +# Include the progress variables for this target. +include src/CMakeFiles/raspicam.dir/progress.make + +# Include the compile flags for this target's objects. +include src/CMakeFiles/raspicam.dir/flags.make + +src/CMakeFiles/raspicam.dir/raspicam.cpp.o: src/CMakeFiles/raspicam.dir/flags.make +src/CMakeFiles/raspicam.dir/raspicam.cpp.o: ../src/raspicam.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles $(CMAKE_PROGRESS_1) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object src/CMakeFiles/raspicam.dir/raspicam.cpp.o" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/raspicam.dir/raspicam.cpp.o -c /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicam.cpp + +src/CMakeFiles/raspicam.dir/raspicam.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/raspicam.dir/raspicam.cpp.i" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicam.cpp > CMakeFiles/raspicam.dir/raspicam.cpp.i + +src/CMakeFiles/raspicam.dir/raspicam.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/raspicam.dir/raspicam.cpp.s" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicam.cpp -o CMakeFiles/raspicam.dir/raspicam.cpp.s + +src/CMakeFiles/raspicam.dir/raspicam.cpp.o.requires: +.PHONY : src/CMakeFiles/raspicam.dir/raspicam.cpp.o.requires + +src/CMakeFiles/raspicam.dir/raspicam.cpp.o.provides: src/CMakeFiles/raspicam.dir/raspicam.cpp.o.requires + $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/raspicam.cpp.o.provides.build +.PHONY : src/CMakeFiles/raspicam.dir/raspicam.cpp.o.provides + +src/CMakeFiles/raspicam.dir/raspicam.cpp.o.provides.build: src/CMakeFiles/raspicam.dir/raspicam.cpp.o + +src/CMakeFiles/raspicam.dir/raspicam_still.cpp.o: src/CMakeFiles/raspicam.dir/flags.make +src/CMakeFiles/raspicam.dir/raspicam_still.cpp.o: ../src/raspicam_still.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles $(CMAKE_PROGRESS_2) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object src/CMakeFiles/raspicam.dir/raspicam_still.cpp.o" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/raspicam.dir/raspicam_still.cpp.o -c /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicam_still.cpp + +src/CMakeFiles/raspicam.dir/raspicam_still.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/raspicam.dir/raspicam_still.cpp.i" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicam_still.cpp > CMakeFiles/raspicam.dir/raspicam_still.cpp.i + +src/CMakeFiles/raspicam.dir/raspicam_still.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/raspicam.dir/raspicam_still.cpp.s" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicam_still.cpp -o CMakeFiles/raspicam.dir/raspicam_still.cpp.s + +src/CMakeFiles/raspicam.dir/raspicam_still.cpp.o.requires: +.PHONY : src/CMakeFiles/raspicam.dir/raspicam_still.cpp.o.requires + +src/CMakeFiles/raspicam.dir/raspicam_still.cpp.o.provides: src/CMakeFiles/raspicam.dir/raspicam_still.cpp.o.requires + $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/raspicam_still.cpp.o.provides.build +.PHONY : src/CMakeFiles/raspicam.dir/raspicam_still.cpp.o.provides + +src/CMakeFiles/raspicam.dir/raspicam_still.cpp.o.provides.build: src/CMakeFiles/raspicam.dir/raspicam_still.cpp.o + +src/CMakeFiles/raspicam.dir/private/private_impl.cpp.o: src/CMakeFiles/raspicam.dir/flags.make +src/CMakeFiles/raspicam.dir/private/private_impl.cpp.o: ../src/private/private_impl.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles $(CMAKE_PROGRESS_3) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object src/CMakeFiles/raspicam.dir/private/private_impl.cpp.o" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/raspicam.dir/private/private_impl.cpp.o -c /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/private/private_impl.cpp + +src/CMakeFiles/raspicam.dir/private/private_impl.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/raspicam.dir/private/private_impl.cpp.i" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/private/private_impl.cpp > CMakeFiles/raspicam.dir/private/private_impl.cpp.i + +src/CMakeFiles/raspicam.dir/private/private_impl.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/raspicam.dir/private/private_impl.cpp.s" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/private/private_impl.cpp -o CMakeFiles/raspicam.dir/private/private_impl.cpp.s + +src/CMakeFiles/raspicam.dir/private/private_impl.cpp.o.requires: +.PHONY : src/CMakeFiles/raspicam.dir/private/private_impl.cpp.o.requires + +src/CMakeFiles/raspicam.dir/private/private_impl.cpp.o.provides: src/CMakeFiles/raspicam.dir/private/private_impl.cpp.o.requires + $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/private/private_impl.cpp.o.provides.build +.PHONY : src/CMakeFiles/raspicam.dir/private/private_impl.cpp.o.provides + +src/CMakeFiles/raspicam.dir/private/private_impl.cpp.o.provides.build: src/CMakeFiles/raspicam.dir/private/private_impl.cpp.o + +src/CMakeFiles/raspicam.dir/private/threadcondition.cpp.o: src/CMakeFiles/raspicam.dir/flags.make +src/CMakeFiles/raspicam.dir/private/threadcondition.cpp.o: ../src/private/threadcondition.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles $(CMAKE_PROGRESS_4) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object src/CMakeFiles/raspicam.dir/private/threadcondition.cpp.o" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/raspicam.dir/private/threadcondition.cpp.o -c /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/private/threadcondition.cpp + +src/CMakeFiles/raspicam.dir/private/threadcondition.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/raspicam.dir/private/threadcondition.cpp.i" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/private/threadcondition.cpp > CMakeFiles/raspicam.dir/private/threadcondition.cpp.i + +src/CMakeFiles/raspicam.dir/private/threadcondition.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/raspicam.dir/private/threadcondition.cpp.s" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/private/threadcondition.cpp -o CMakeFiles/raspicam.dir/private/threadcondition.cpp.s + +src/CMakeFiles/raspicam.dir/private/threadcondition.cpp.o.requires: +.PHONY : src/CMakeFiles/raspicam.dir/private/threadcondition.cpp.o.requires + +src/CMakeFiles/raspicam.dir/private/threadcondition.cpp.o.provides: src/CMakeFiles/raspicam.dir/private/threadcondition.cpp.o.requires + $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/private/threadcondition.cpp.o.provides.build +.PHONY : src/CMakeFiles/raspicam.dir/private/threadcondition.cpp.o.provides + +src/CMakeFiles/raspicam.dir/private/threadcondition.cpp.o.provides.build: src/CMakeFiles/raspicam.dir/private/threadcondition.cpp.o + +src/CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.o: src/CMakeFiles/raspicam.dir/flags.make +src/CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.o: ../src/private_still/private_still_impl.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles $(CMAKE_PROGRESS_5) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object src/CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.o" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.o -c /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/private_still/private_still_impl.cpp + +src/CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.i" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/private_still/private_still_impl.cpp > CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.i + +src/CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.s" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/private_still/private_still_impl.cpp -o CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.s + +src/CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.o.requires: +.PHONY : src/CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.o.requires + +src/CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.o.provides: src/CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.o.requires + $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.o.provides.build +.PHONY : src/CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.o.provides + +src/CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.o.provides.build: src/CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.o + +# Object files for target raspicam +raspicam_OBJECTS = \ +"CMakeFiles/raspicam.dir/raspicam.cpp.o" \ +"CMakeFiles/raspicam.dir/raspicam_still.cpp.o" \ +"CMakeFiles/raspicam.dir/private/private_impl.cpp.o" \ +"CMakeFiles/raspicam.dir/private/threadcondition.cpp.o" \ +"CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.o" + +# External object files for target raspicam +raspicam_EXTERNAL_OBJECTS = + +src/libraspicam.so.0.1.2: src/CMakeFiles/raspicam.dir/raspicam.cpp.o +src/libraspicam.so.0.1.2: src/CMakeFiles/raspicam.dir/raspicam_still.cpp.o +src/libraspicam.so.0.1.2: src/CMakeFiles/raspicam.dir/private/private_impl.cpp.o +src/libraspicam.so.0.1.2: src/CMakeFiles/raspicam.dir/private/threadcondition.cpp.o +src/libraspicam.so.0.1.2: src/CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.o +src/libraspicam.so.0.1.2: src/CMakeFiles/raspicam.dir/build.make +src/libraspicam.so.0.1.2: /opt/vc/lib/libmmal_core.so +src/libraspicam.so.0.1.2: /opt/vc/lib/libmmal_util.so +src/libraspicam.so.0.1.2: /opt/vc/lib/libmmal.so +src/libraspicam.so.0.1.2: src/CMakeFiles/raspicam.dir/link.txt + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --red --bold "Linking CXX shared library libraspicam.so" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/raspicam.dir/link.txt --verbose=$(VERBOSE) + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && $(CMAKE_COMMAND) -E cmake_symlink_library libraspicam.so.0.1.2 libraspicam.so.0.1 libraspicam.so + +src/libraspicam.so.0.1: src/libraspicam.so.0.1.2 + +src/libraspicam.so: src/libraspicam.so.0.1.2 + +# Rule to build all files generated by this target. +src/CMakeFiles/raspicam.dir/build: src/libraspicam.so +.PHONY : src/CMakeFiles/raspicam.dir/build + +src/CMakeFiles/raspicam.dir/requires: src/CMakeFiles/raspicam.dir/raspicam.cpp.o.requires +src/CMakeFiles/raspicam.dir/requires: src/CMakeFiles/raspicam.dir/raspicam_still.cpp.o.requires +src/CMakeFiles/raspicam.dir/requires: src/CMakeFiles/raspicam.dir/private/private_impl.cpp.o.requires +src/CMakeFiles/raspicam.dir/requires: src/CMakeFiles/raspicam.dir/private/threadcondition.cpp.o.requires +src/CMakeFiles/raspicam.dir/requires: src/CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.o.requires +.PHONY : src/CMakeFiles/raspicam.dir/requires + +src/CMakeFiles/raspicam.dir/clean: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && $(CMAKE_COMMAND) -P CMakeFiles/raspicam.dir/cmake_clean.cmake +.PHONY : src/CMakeFiles/raspicam.dir/clean + +src/CMakeFiles/raspicam.dir/depend: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /home/ubuntu/Nomad/external_src/raspicam-0.1.3 /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : src/CMakeFiles/raspicam.dir/depend + diff --git a/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/cmake_clean.cmake b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/cmake_clean.cmake new file mode 100644 index 0000000..a8e1843 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/cmake_clean.cmake @@ -0,0 +1,16 @@ +FILE(REMOVE_RECURSE + "CMakeFiles/raspicam.dir/raspicam.cpp.o" + "CMakeFiles/raspicam.dir/raspicam_still.cpp.o" + "CMakeFiles/raspicam.dir/private/private_impl.cpp.o" + "CMakeFiles/raspicam.dir/private/threadcondition.cpp.o" + "CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.o" + "libraspicam.pdb" + "libraspicam.so" + "libraspicam.so.0.1.2" + "libraspicam.so.0.1" +) + +# Per-language clean rules from dependency scanning. +FOREACH(lang CXX) + INCLUDE(CMakeFiles/raspicam.dir/cmake_clean_${lang}.cmake OPTIONAL) +ENDFOREACH(lang) diff --git a/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/depend.make b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/depend.make new file mode 100644 index 0000000..ea0f1d8 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/depend.make @@ -0,0 +1,2 @@ +# Empty dependencies file for raspicam. +# This may be replaced when dependencies are built. diff --git a/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/flags.make b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/flags.make new file mode 100644 index 0000000..d84e64e --- /dev/null +++ b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/flags.make @@ -0,0 +1,8 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# compile CXX with /usr/bin/c++ +CXX_FLAGS = -std=c++0x -Wl,--no-as-needed -Wall -ffunction-sections -fomit-frame-pointer -O2 -ffast-math -DNDEBUG -lpthread -fPIC -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/dependencies -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/dependencies/mmal -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/dependencies/vcos -I/usr/local/include/opencv -I/usr/local/include -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/. -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src + +CXX_DEFINES = -DDSO_EXPORTS + diff --git a/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/link.txt b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/link.txt new file mode 100644 index 0000000..c722a1f --- /dev/null +++ b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/link.txt @@ -0,0 +1 @@ +/usr/bin/c++ -fPIC -std=c++0x -Wl,--no-as-needed -Wall -ffunction-sections -fomit-frame-pointer -O2 -ffast-math -DNDEBUG -lpthread -shared -Wl,-soname,libraspicam.so.0.1 -o libraspicam.so.0.1.2 CMakeFiles/raspicam.dir/raspicam.cpp.o CMakeFiles/raspicam.dir/raspicam_still.cpp.o CMakeFiles/raspicam.dir/private/private_impl.cpp.o CMakeFiles/raspicam.dir/private/threadcondition.cpp.o CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.o /opt/vc/lib/libmmal_core.so /opt/vc/lib/libmmal_util.so /opt/vc/lib/libmmal.so -Wl,-rpath,/opt/vc/lib: diff --git a/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/progress.make b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/progress.make new file mode 100644 index 0000000..33e6bff --- /dev/null +++ b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/progress.make @@ -0,0 +1,6 @@ +CMAKE_PROGRESS_1 = 1 +CMAKE_PROGRESS_2 = 2 +CMAKE_PROGRESS_3 = 3 +CMAKE_PROGRESS_4 = 4 +CMAKE_PROGRESS_5 = 5 + diff --git a/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/DependInfo.cmake b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/DependInfo.cmake new file mode 100644 index 0000000..6b2ac46 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/DependInfo.cmake @@ -0,0 +1,28 @@ +# The set of languages for which implicit dependencies are needed: +SET(CMAKE_DEPENDS_LANGUAGES + "CXX" + ) +# The set of files for implicit dependencies of each language: +SET(CMAKE_DEPENDS_CHECK_CXX + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicam_cv.cpp" "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.o" + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicam_still_cv.cpp" "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.o" + ) +SET(CMAKE_CXX_COMPILER_ID "GNU") + +# Targets to which this target links. +SET(CMAKE_TARGET_LINKED_INFO_FILES + ) + +# The include file search paths: +SET(CMAKE_C_TARGET_INCLUDE_PATH + "../dependencies" + "../dependencies/mmal" + "../dependencies/vcos" + "/usr/local/include/opencv" + "/usr/local/include" + "../src/." + "src" + ) +SET(CMAKE_CXX_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_Fortran_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_ASM_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) diff --git a/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/build.make b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/build.make new file mode 100644 index 0000000..4221015 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/build.make @@ -0,0 +1,158 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E remove -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build + +# Include any dependencies generated for this target. +include src/CMakeFiles/raspicam_cv.dir/depend.make + +# Include the progress variables for this target. +include src/CMakeFiles/raspicam_cv.dir/progress.make + +# Include the compile flags for this target's objects. +include src/CMakeFiles/raspicam_cv.dir/flags.make + +src/CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.o: src/CMakeFiles/raspicam_cv.dir/flags.make +src/CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.o: ../src/raspicam_cv.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles $(CMAKE_PROGRESS_1) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object src/CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.o" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.o -c /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicam_cv.cpp + +src/CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.i" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicam_cv.cpp > CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.i + +src/CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.s" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicam_cv.cpp -o CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.s + +src/CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.o.requires: +.PHONY : src/CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.o.requires + +src/CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.o.provides: src/CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.o.requires + $(MAKE) -f src/CMakeFiles/raspicam_cv.dir/build.make src/CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.o.provides.build +.PHONY : src/CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.o.provides + +src/CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.o.provides.build: src/CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.o + +src/CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.o: src/CMakeFiles/raspicam_cv.dir/flags.make +src/CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.o: ../src/raspicam_still_cv.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles $(CMAKE_PROGRESS_2) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object src/CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.o" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.o -c /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicam_still_cv.cpp + +src/CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.i" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicam_still_cv.cpp > CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.i + +src/CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.s" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicam_still_cv.cpp -o CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.s + +src/CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.o.requires: +.PHONY : src/CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.o.requires + +src/CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.o.provides: src/CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.o.requires + $(MAKE) -f src/CMakeFiles/raspicam_cv.dir/build.make src/CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.o.provides.build +.PHONY : src/CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.o.provides + +src/CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.o.provides.build: src/CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.o + +# Object files for target raspicam_cv +raspicam_cv_OBJECTS = \ +"CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.o" \ +"CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.o" + +# External object files for target raspicam_cv +raspicam_cv_EXTERNAL_OBJECTS = + +src/libraspicam_cv.so: src/CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.o +src/libraspicam_cv.so: src/CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.o +src/libraspicam_cv.so: src/CMakeFiles/raspicam_cv.dir/build.make +src/libraspicam_cv.so: /opt/vc/lib/libmmal_core.so +src/libraspicam_cv.so: /opt/vc/lib/libmmal_util.so +src/libraspicam_cv.so: /opt/vc/lib/libmmal.so +src/libraspicam_cv.so: /usr/local/lib/libopencv_videostab.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_videoio.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_video.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_superres.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_stitching.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_shape.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_photo.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_objdetect.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_ml.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_imgproc.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_imgcodecs.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_highgui.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_hal.a +src/libraspicam_cv.so: /usr/local/lib/libopencv_flann.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_features2d.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_core.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_calib3d.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_features2d.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_ml.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_highgui.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_videoio.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_imgcodecs.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_flann.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_video.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_imgproc.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_core.so.3.0.0 +src/libraspicam_cv.so: /usr/local/lib/libopencv_hal.a +src/libraspicam_cv.so: src/CMakeFiles/raspicam_cv.dir/link.txt + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --red --bold "Linking CXX shared library libraspicam_cv.so" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/raspicam_cv.dir/link.txt --verbose=$(VERBOSE) + +# Rule to build all files generated by this target. +src/CMakeFiles/raspicam_cv.dir/build: src/libraspicam_cv.so +.PHONY : src/CMakeFiles/raspicam_cv.dir/build + +src/CMakeFiles/raspicam_cv.dir/requires: src/CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.o.requires +src/CMakeFiles/raspicam_cv.dir/requires: src/CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.o.requires +.PHONY : src/CMakeFiles/raspicam_cv.dir/requires + +src/CMakeFiles/raspicam_cv.dir/clean: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src && $(CMAKE_COMMAND) -P CMakeFiles/raspicam_cv.dir/cmake_clean.cmake +.PHONY : src/CMakeFiles/raspicam_cv.dir/clean + +src/CMakeFiles/raspicam_cv.dir/depend: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /home/ubuntu/Nomad/external_src/raspicam-0.1.3 /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : src/CMakeFiles/raspicam_cv.dir/depend + diff --git a/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/cmake_clean.cmake b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/cmake_clean.cmake new file mode 100644 index 0000000..b485852 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/cmake_clean.cmake @@ -0,0 +1,11 @@ +FILE(REMOVE_RECURSE + "CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.o" + "CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.o" + "libraspicam_cv.pdb" + "libraspicam_cv.so" +) + +# Per-language clean rules from dependency scanning. +FOREACH(lang CXX) + INCLUDE(CMakeFiles/raspicam_cv.dir/cmake_clean_${lang}.cmake OPTIONAL) +ENDFOREACH(lang) diff --git a/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/depend.make b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/depend.make new file mode 100644 index 0000000..3e54adb --- /dev/null +++ b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/depend.make @@ -0,0 +1,2 @@ +# Empty dependencies file for raspicam_cv. +# This may be replaced when dependencies are built. diff --git a/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/flags.make b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/flags.make new file mode 100644 index 0000000..62522a7 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/flags.make @@ -0,0 +1,8 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# compile CXX with /usr/bin/c++ +CXX_FLAGS = -std=c++0x -Wl,--no-as-needed -Wall -ffunction-sections -fomit-frame-pointer -O2 -ffast-math -DNDEBUG -lpthread -fPIC -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/dependencies -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/dependencies/mmal -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/dependencies/vcos -I/usr/local/include/opencv -I/usr/local/include -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/. -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src + +CXX_DEFINES = -Draspicam_cv_EXPORTS + diff --git a/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/link.txt b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/link.txt new file mode 100644 index 0000000..966b7a8 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/link.txt @@ -0,0 +1 @@ +/usr/bin/c++ -fPIC -std=c++0x -Wl,--no-as-needed -Wall -ffunction-sections -fomit-frame-pointer -O2 -ffast-math -DNDEBUG -lpthread -shared -Wl,-soname,libraspicam_cv.so -o libraspicam_cv.so CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.o CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.o /opt/vc/lib/libmmal_core.so /opt/vc/lib/libmmal_util.so /opt/vc/lib/libmmal.so /usr/local/lib/libopencv_videostab.so.3.0.0 /usr/local/lib/libopencv_videoio.so.3.0.0 /usr/local/lib/libopencv_video.so.3.0.0 /usr/local/lib/libopencv_superres.so.3.0.0 /usr/local/lib/libopencv_stitching.so.3.0.0 /usr/local/lib/libopencv_shape.so.3.0.0 /usr/local/lib/libopencv_photo.so.3.0.0 /usr/local/lib/libopencv_objdetect.so.3.0.0 /usr/local/lib/libopencv_ml.so.3.0.0 /usr/local/lib/libopencv_imgproc.so.3.0.0 /usr/local/lib/libopencv_imgcodecs.so.3.0.0 /usr/local/lib/libopencv_highgui.so.3.0.0 /usr/local/lib/libopencv_hal.a /usr/local/lib/libopencv_flann.so.3.0.0 /usr/local/lib/libopencv_features2d.so.3.0.0 /usr/local/lib/libopencv_core.so.3.0.0 /usr/local/lib/libopencv_calib3d.so.3.0.0 /usr/local/lib/libopencv_features2d.so.3.0.0 /usr/local/lib/libopencv_ml.so.3.0.0 /usr/local/lib/libopencv_highgui.so.3.0.0 /usr/local/lib/libopencv_videoio.so.3.0.0 /usr/local/lib/libopencv_imgcodecs.so.3.0.0 /usr/local/lib/libopencv_flann.so.3.0.0 /usr/local/lib/libopencv_video.so.3.0.0 /usr/local/lib/libopencv_imgproc.so.3.0.0 /usr/local/lib/libopencv_core.so.3.0.0 /usr/local/lib/libopencv_hal.a -ldl -lm -lpthread -lrt -Wl,-rpath,/opt/vc/lib:/usr/local/lib: diff --git a/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/progress.make b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/progress.make new file mode 100644 index 0000000..8808896 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/progress.make @@ -0,0 +1,3 @@ +CMAKE_PROGRESS_1 = 6 +CMAKE_PROGRESS_2 = 7 + diff --git a/external_src/raspicam-0.1.3/build/src/Makefile b/external_src/raspicam-0.1.3/build/src/Makefile new file mode 100644 index 0000000..26c30cd --- /dev/null +++ b/external_src/raspicam-0.1.3/build/src/Makefile @@ -0,0 +1,386 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E remove -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running interactive CMake command-line interface..." + /usr/bin/cmake -i . +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache +.PHONY : edit_cache/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /usr/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /usr/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: install/local +.PHONY : install/local/fast + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: install/strip +.PHONY : install/strip/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\" \"main\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components +.PHONY : list_install_components/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /usr/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache +.PHONY : rebuild_cache/fast + +# The main all target +all: cmake_check_build_system + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/CMakeFiles/progress.marks + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f CMakeFiles/Makefile2 src/all + $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f CMakeFiles/Makefile2 src/clean +.PHONY : clean + +# The main clean target +clean/fast: clean +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f CMakeFiles/Makefile2 src/preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f CMakeFiles/Makefile2 src/preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +# Convenience name for target. +src/CMakeFiles/raspicam.dir/rule: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f CMakeFiles/Makefile2 src/CMakeFiles/raspicam.dir/rule +.PHONY : src/CMakeFiles/raspicam.dir/rule + +# Convenience name for target. +raspicam: src/CMakeFiles/raspicam.dir/rule +.PHONY : raspicam + +# fast build rule for target. +raspicam/fast: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/build +.PHONY : raspicam/fast + +# Convenience name for target. +src/CMakeFiles/raspicam_cv.dir/rule: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f CMakeFiles/Makefile2 src/CMakeFiles/raspicam_cv.dir/rule +.PHONY : src/CMakeFiles/raspicam_cv.dir/rule + +# Convenience name for target. +raspicam_cv: src/CMakeFiles/raspicam_cv.dir/rule +.PHONY : raspicam_cv + +# fast build rule for target. +raspicam_cv/fast: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam_cv.dir/build.make src/CMakeFiles/raspicam_cv.dir/build +.PHONY : raspicam_cv/fast + +private/private_impl.o: private/private_impl.cpp.o +.PHONY : private/private_impl.o + +# target to build an object file +private/private_impl.cpp.o: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/private/private_impl.cpp.o +.PHONY : private/private_impl.cpp.o + +private/private_impl.i: private/private_impl.cpp.i +.PHONY : private/private_impl.i + +# target to preprocess a source file +private/private_impl.cpp.i: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/private/private_impl.cpp.i +.PHONY : private/private_impl.cpp.i + +private/private_impl.s: private/private_impl.cpp.s +.PHONY : private/private_impl.s + +# target to generate assembly for a file +private/private_impl.cpp.s: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/private/private_impl.cpp.s +.PHONY : private/private_impl.cpp.s + +private/threadcondition.o: private/threadcondition.cpp.o +.PHONY : private/threadcondition.o + +# target to build an object file +private/threadcondition.cpp.o: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/private/threadcondition.cpp.o +.PHONY : private/threadcondition.cpp.o + +private/threadcondition.i: private/threadcondition.cpp.i +.PHONY : private/threadcondition.i + +# target to preprocess a source file +private/threadcondition.cpp.i: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/private/threadcondition.cpp.i +.PHONY : private/threadcondition.cpp.i + +private/threadcondition.s: private/threadcondition.cpp.s +.PHONY : private/threadcondition.s + +# target to generate assembly for a file +private/threadcondition.cpp.s: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/private/threadcondition.cpp.s +.PHONY : private/threadcondition.cpp.s + +private_still/private_still_impl.o: private_still/private_still_impl.cpp.o +.PHONY : private_still/private_still_impl.o + +# target to build an object file +private_still/private_still_impl.cpp.o: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.o +.PHONY : private_still/private_still_impl.cpp.o + +private_still/private_still_impl.i: private_still/private_still_impl.cpp.i +.PHONY : private_still/private_still_impl.i + +# target to preprocess a source file +private_still/private_still_impl.cpp.i: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.i +.PHONY : private_still/private_still_impl.cpp.i + +private_still/private_still_impl.s: private_still/private_still_impl.cpp.s +.PHONY : private_still/private_still_impl.s + +# target to generate assembly for a file +private_still/private_still_impl.cpp.s: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/private_still/private_still_impl.cpp.s +.PHONY : private_still/private_still_impl.cpp.s + +raspicam.o: raspicam.cpp.o +.PHONY : raspicam.o + +# target to build an object file +raspicam.cpp.o: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/raspicam.cpp.o +.PHONY : raspicam.cpp.o + +raspicam.i: raspicam.cpp.i +.PHONY : raspicam.i + +# target to preprocess a source file +raspicam.cpp.i: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/raspicam.cpp.i +.PHONY : raspicam.cpp.i + +raspicam.s: raspicam.cpp.s +.PHONY : raspicam.s + +# target to generate assembly for a file +raspicam.cpp.s: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/raspicam.cpp.s +.PHONY : raspicam.cpp.s + +raspicam_cv.o: raspicam_cv.cpp.o +.PHONY : raspicam_cv.o + +# target to build an object file +raspicam_cv.cpp.o: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam_cv.dir/build.make src/CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.o +.PHONY : raspicam_cv.cpp.o + +raspicam_cv.i: raspicam_cv.cpp.i +.PHONY : raspicam_cv.i + +# target to preprocess a source file +raspicam_cv.cpp.i: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam_cv.dir/build.make src/CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.i +.PHONY : raspicam_cv.cpp.i + +raspicam_cv.s: raspicam_cv.cpp.s +.PHONY : raspicam_cv.s + +# target to generate assembly for a file +raspicam_cv.cpp.s: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam_cv.dir/build.make src/CMakeFiles/raspicam_cv.dir/raspicam_cv.cpp.s +.PHONY : raspicam_cv.cpp.s + +raspicam_still.o: raspicam_still.cpp.o +.PHONY : raspicam_still.o + +# target to build an object file +raspicam_still.cpp.o: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/raspicam_still.cpp.o +.PHONY : raspicam_still.cpp.o + +raspicam_still.i: raspicam_still.cpp.i +.PHONY : raspicam_still.i + +# target to preprocess a source file +raspicam_still.cpp.i: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/raspicam_still.cpp.i +.PHONY : raspicam_still.cpp.i + +raspicam_still.s: raspicam_still.cpp.s +.PHONY : raspicam_still.s + +# target to generate assembly for a file +raspicam_still.cpp.s: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam.dir/build.make src/CMakeFiles/raspicam.dir/raspicam_still.cpp.s +.PHONY : raspicam_still.cpp.s + +raspicam_still_cv.o: raspicam_still_cv.cpp.o +.PHONY : raspicam_still_cv.o + +# target to build an object file +raspicam_still_cv.cpp.o: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam_cv.dir/build.make src/CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.o +.PHONY : raspicam_still_cv.cpp.o + +raspicam_still_cv.i: raspicam_still_cv.cpp.i +.PHONY : raspicam_still_cv.i + +# target to preprocess a source file +raspicam_still_cv.cpp.i: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam_cv.dir/build.make src/CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.i +.PHONY : raspicam_still_cv.cpp.i + +raspicam_still_cv.s: raspicam_still_cv.cpp.s +.PHONY : raspicam_still_cv.s + +# target to generate assembly for a file +raspicam_still_cv.cpp.s: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f src/CMakeFiles/raspicam_cv.dir/build.make src/CMakeFiles/raspicam_cv.dir/raspicam_still_cv.cpp.s +.PHONY : raspicam_still_cv.cpp.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... install" + @echo "... install/local" + @echo "... install/strip" + @echo "... list_install_components" + @echo "... raspicam" + @echo "... raspicam_cv" + @echo "... rebuild_cache" + @echo "... private/private_impl.o" + @echo "... private/private_impl.i" + @echo "... private/private_impl.s" + @echo "... private/threadcondition.o" + @echo "... private/threadcondition.i" + @echo "... private/threadcondition.s" + @echo "... private_still/private_still_impl.o" + @echo "... private_still/private_still_impl.i" + @echo "... private_still/private_still_impl.s" + @echo "... raspicam.o" + @echo "... raspicam.i" + @echo "... raspicam.s" + @echo "... raspicam_cv.o" + @echo "... raspicam_cv.i" + @echo "... raspicam_cv.s" + @echo "... raspicam_still.o" + @echo "... raspicam_still.i" + @echo "... raspicam_still.s" + @echo "... raspicam_still_cv.o" + @echo "... raspicam_still_cv.i" + @echo "... raspicam_still_cv.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/external_src/raspicam-0.1.3/build/src/cmake_install.cmake b/external_src/raspicam-0.1.3/build/src/cmake_install.cmake new file mode 100644 index 0000000..9be51a1 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/src/cmake_install.cmake @@ -0,0 +1,95 @@ +# Install script for directory: /home/ubuntu/Nomad/external_src/raspicam-0.1.3/src + +# Set the install prefix +IF(NOT DEFINED CMAKE_INSTALL_PREFIX) + SET(CMAKE_INSTALL_PREFIX "/usr/local") +ENDIF(NOT DEFINED CMAKE_INSTALL_PREFIX) +STRING(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +IF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + IF(BUILD_TYPE) + STRING(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + ELSE(BUILD_TYPE) + SET(CMAKE_INSTALL_CONFIG_NAME "Release") + ENDIF(BUILD_TYPE) + MESSAGE(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +ENDIF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + +# Set the component getting installed. +IF(NOT CMAKE_INSTALL_COMPONENT) + IF(COMPONENT) + MESSAGE(STATUS "Install component: \"${COMPONENT}\"") + SET(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + ELSE(COMPONENT) + SET(CMAKE_INSTALL_COMPONENT) + ENDIF(COMPONENT) +ENDIF(NOT CMAKE_INSTALL_COMPONENT) + +# Install shared libraries without execute permission? +IF(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) + SET(CMAKE_INSTALL_SO_NO_EXE "1") +ENDIF(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) + +IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + FOREACH(file + "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libraspicam.so.0.1.2" + "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libraspicam.so.0.1" + "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libraspicam.so" + ) + IF(EXISTS "${file}" AND + NOT IS_SYMLINK "${file}") + FILE(RPATH_CHECK + FILE "${file}" + RPATH "") + ENDIF() + ENDFOREACH() + FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" TYPE SHARED_LIBRARY PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE FILES + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/libraspicam.so.0.1.2" + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/libraspicam.so.0.1" + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/libraspicam.so" + ) + FOREACH(file + "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libraspicam.so.0.1.2" + "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libraspicam.so.0.1" + "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libraspicam.so" + ) + IF(EXISTS "${file}" AND + NOT IS_SYMLINK "${file}") + FILE(RPATH_REMOVE + FILE "${file}") + IF(CMAKE_INSTALL_DO_STRIP) + EXECUTE_PROCESS(COMMAND "/usr/bin/strip" "${file}") + ENDIF(CMAKE_INSTALL_DO_STRIP) + ENDIF() + ENDFOREACH() +ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + +IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + IF(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libraspicam_cv.so" AND + NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libraspicam_cv.so") + FILE(RPATH_CHECK + FILE "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libraspicam_cv.so" + RPATH "") + ENDIF() + FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" TYPE SHARED_LIBRARY PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE FILES "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/libraspicam_cv.so") + IF(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libraspicam_cv.so" AND + NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libraspicam_cv.so") + FILE(RPATH_REMOVE + FILE "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libraspicam_cv.so") + IF(CMAKE_INSTALL_DO_STRIP) + EXECUTE_PROCESS(COMMAND "/usr/bin/strip" "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libraspicam_cv.so") + ENDIF(CMAKE_INSTALL_DO_STRIP) + ENDIF() +ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + +IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/include/raspicam" TYPE FILE FILES + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicamtypes.h" + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicam.h" + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicam_cv.h" + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/src/raspicam_still_cv.h" + ) +ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "main") + diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/CMakeDirectoryInformation.cmake b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/CMakeDirectoryInformation.cmake new file mode 100644 index 0000000..24120d7 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/CMakeDirectoryInformation.cmake @@ -0,0 +1,16 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Relative path conversion top directories. +SET(CMAKE_RELATIVE_PATH_TOP_SOURCE "/home/ubuntu/Nomad/external_src/raspicam-0.1.3") +SET(CMAKE_RELATIVE_PATH_TOP_BINARY "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build") + +# Force unix paths in dependencies. +SET(CMAKE_FORCE_UNIX_PATHS 1) + + +# The C and CXX include file regular expressions for this directory. +SET(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$") +SET(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$") +SET(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN}) +SET(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN}) diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/progress.marks b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/progress.marks new file mode 100644 index 0000000..b4de394 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/progress.marks @@ -0,0 +1 @@ +11 diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/DependInfo.cmake b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/DependInfo.cmake new file mode 100644 index 0000000..d6e3d31 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/DependInfo.cmake @@ -0,0 +1,28 @@ +# The set of languages for which implicit dependencies are needed: +SET(CMAKE_DEPENDS_LANGUAGES + "CXX" + ) +# The set of files for implicit dependencies of each language: +SET(CMAKE_DEPENDS_CHECK_CXX + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils/raspicam_cv_still_test.cpp" "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.o" + ) +SET(CMAKE_CXX_COMPILER_ID "GNU") + +# Targets to which this target links. +SET(CMAKE_TARGET_LINKED_INFO_FILES + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/DependInfo.cmake" + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/DependInfo.cmake" + ) + +# The include file search paths: +SET(CMAKE_C_TARGET_INCLUDE_PATH + "../dependencies" + "../dependencies/mmal" + "../dependencies/vcos" + "/usr/local/include/opencv" + "/usr/local/include" + "../src" + ) +SET(CMAKE_CXX_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_Fortran_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_ASM_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/build.make b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/build.make new file mode 100644 index 0000000..6322cd7 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/build.make @@ -0,0 +1,124 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E remove -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build + +# Include any dependencies generated for this target. +include utils/CMakeFiles/raspicam_cv_still_test.dir/depend.make + +# Include the progress variables for this target. +include utils/CMakeFiles/raspicam_cv_still_test.dir/progress.make + +# Include the compile flags for this target's objects. +include utils/CMakeFiles/raspicam_cv_still_test.dir/flags.make + +utils/CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.o: utils/CMakeFiles/raspicam_cv_still_test.dir/flags.make +utils/CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.o: ../utils/raspicam_cv_still_test.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles $(CMAKE_PROGRESS_1) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object utils/CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.o" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.o -c /home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils/raspicam_cv_still_test.cpp + +utils/CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.i" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils/raspicam_cv_still_test.cpp > CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.i + +utils/CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.s" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils/raspicam_cv_still_test.cpp -o CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.s + +utils/CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.o.requires: +.PHONY : utils/CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.o.requires + +utils/CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.o.provides: utils/CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.o.requires + $(MAKE) -f utils/CMakeFiles/raspicam_cv_still_test.dir/build.make utils/CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.o.provides.build +.PHONY : utils/CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.o.provides + +utils/CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.o.provides.build: utils/CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.o + +# Object files for target raspicam_cv_still_test +raspicam_cv_still_test_OBJECTS = \ +"CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.o" + +# External object files for target raspicam_cv_still_test +raspicam_cv_still_test_EXTERNAL_OBJECTS = + +utils/raspicam_cv_still_test: utils/CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.o +utils/raspicam_cv_still_test: utils/CMakeFiles/raspicam_cv_still_test.dir/build.make +utils/raspicam_cv_still_test: src/libraspicam.so.0.1.2 +utils/raspicam_cv_still_test: src/libraspicam_cv.so +utils/raspicam_cv_still_test: /opt/vc/lib/libmmal_core.so +utils/raspicam_cv_still_test: /opt/vc/lib/libmmal_util.so +utils/raspicam_cv_still_test: /opt/vc/lib/libmmal.so +utils/raspicam_cv_still_test: /usr/local/lib/libopencv_videostab.so.3.0.0 +utils/raspicam_cv_still_test: /usr/local/lib/libopencv_superres.so.3.0.0 +utils/raspicam_cv_still_test: /usr/local/lib/libopencv_stitching.so.3.0.0 +utils/raspicam_cv_still_test: /usr/local/lib/libopencv_shape.so.3.0.0 +utils/raspicam_cv_still_test: /usr/local/lib/libopencv_video.so.3.0.0 +utils/raspicam_cv_still_test: /usr/local/lib/libopencv_photo.so.3.0.0 +utils/raspicam_cv_still_test: /usr/local/lib/libopencv_objdetect.so.3.0.0 +utils/raspicam_cv_still_test: /usr/local/lib/libopencv_calib3d.so.3.0.0 +utils/raspicam_cv_still_test: /usr/local/lib/libopencv_features2d.so.3.0.0 +utils/raspicam_cv_still_test: /usr/local/lib/libopencv_ml.so.3.0.0 +utils/raspicam_cv_still_test: /usr/local/lib/libopencv_highgui.so.3.0.0 +utils/raspicam_cv_still_test: /usr/local/lib/libopencv_videoio.so.3.0.0 +utils/raspicam_cv_still_test: /usr/local/lib/libopencv_imgcodecs.so.3.0.0 +utils/raspicam_cv_still_test: /usr/local/lib/libopencv_imgproc.so.3.0.0 +utils/raspicam_cv_still_test: /usr/local/lib/libopencv_flann.so.3.0.0 +utils/raspicam_cv_still_test: /usr/local/lib/libopencv_core.so.3.0.0 +utils/raspicam_cv_still_test: /usr/local/lib/libopencv_hal.a +utils/raspicam_cv_still_test: utils/CMakeFiles/raspicam_cv_still_test.dir/link.txt + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --red --bold "Linking CXX executable raspicam_cv_still_test" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/raspicam_cv_still_test.dir/link.txt --verbose=$(VERBOSE) + +# Rule to build all files generated by this target. +utils/CMakeFiles/raspicam_cv_still_test.dir/build: utils/raspicam_cv_still_test +.PHONY : utils/CMakeFiles/raspicam_cv_still_test.dir/build + +utils/CMakeFiles/raspicam_cv_still_test.dir/requires: utils/CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.o.requires +.PHONY : utils/CMakeFiles/raspicam_cv_still_test.dir/requires + +utils/CMakeFiles/raspicam_cv_still_test.dir/clean: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && $(CMAKE_COMMAND) -P CMakeFiles/raspicam_cv_still_test.dir/cmake_clean.cmake +.PHONY : utils/CMakeFiles/raspicam_cv_still_test.dir/clean + +utils/CMakeFiles/raspicam_cv_still_test.dir/depend: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /home/ubuntu/Nomad/external_src/raspicam-0.1.3 /home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : utils/CMakeFiles/raspicam_cv_still_test.dir/depend + diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/cmake_clean.cmake b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/cmake_clean.cmake new file mode 100644 index 0000000..816a88f --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/cmake_clean.cmake @@ -0,0 +1,10 @@ +FILE(REMOVE_RECURSE + "CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.o" + "raspicam_cv_still_test.pdb" + "raspicam_cv_still_test" +) + +# Per-language clean rules from dependency scanning. +FOREACH(lang CXX) + INCLUDE(CMakeFiles/raspicam_cv_still_test.dir/cmake_clean_${lang}.cmake OPTIONAL) +ENDFOREACH(lang) diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/depend.make b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/depend.make new file mode 100644 index 0000000..501f120 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/depend.make @@ -0,0 +1,2 @@ +# Empty dependencies file for raspicam_cv_still_test. +# This may be replaced when dependencies are built. diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/flags.make b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/flags.make new file mode 100644 index 0000000..1b59b72 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/flags.make @@ -0,0 +1,8 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# compile CXX with /usr/bin/c++ +CXX_FLAGS = -std=c++0x -Wl,--no-as-needed -Wall -ffunction-sections -fomit-frame-pointer -O2 -ffast-math -DNDEBUG -lpthread -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/dependencies -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/dependencies/mmal -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/dependencies/vcos -I/usr/local/include/opencv -I/usr/local/include -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/src + +CXX_DEFINES = + diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/link.txt b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/link.txt new file mode 100644 index 0000000..12b3f94 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/link.txt @@ -0,0 +1 @@ +/usr/bin/c++ -std=c++0x -Wl,--no-as-needed -Wall -ffunction-sections -fomit-frame-pointer -O2 -ffast-math -DNDEBUG -lpthread CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.o -o raspicam_cv_still_test -rdynamic ../src/libraspicam.so.0.1.2 ../src/libraspicam_cv.so /opt/vc/lib/libmmal_core.so /opt/vc/lib/libmmal_util.so /opt/vc/lib/libmmal.so /usr/local/lib/libopencv_videostab.so.3.0.0 /usr/local/lib/libopencv_superres.so.3.0.0 /usr/local/lib/libopencv_stitching.so.3.0.0 /usr/local/lib/libopencv_shape.so.3.0.0 /usr/local/lib/libopencv_video.so.3.0.0 /usr/local/lib/libopencv_photo.so.3.0.0 /usr/local/lib/libopencv_objdetect.so.3.0.0 /usr/local/lib/libopencv_calib3d.so.3.0.0 /usr/local/lib/libopencv_features2d.so.3.0.0 /usr/local/lib/libopencv_ml.so.3.0.0 /usr/local/lib/libopencv_highgui.so.3.0.0 /usr/local/lib/libopencv_videoio.so.3.0.0 /usr/local/lib/libopencv_imgcodecs.so.3.0.0 /usr/local/lib/libopencv_imgproc.so.3.0.0 /usr/local/lib/libopencv_flann.so.3.0.0 /usr/local/lib/libopencv_core.so.3.0.0 /usr/local/lib/libopencv_hal.a -ldl -lm -lpthread -lrt -Wl,-rpath,/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src:/opt/vc/lib:/usr/local/lib: diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/progress.make b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/progress.make new file mode 100644 index 0000000..c561fca --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_still_test.dir/progress.make @@ -0,0 +1,2 @@ +CMAKE_PROGRESS_1 = 8 + diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/DependInfo.cmake b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/DependInfo.cmake new file mode 100644 index 0000000..dfa6818 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/DependInfo.cmake @@ -0,0 +1,28 @@ +# The set of languages for which implicit dependencies are needed: +SET(CMAKE_DEPENDS_LANGUAGES + "CXX" + ) +# The set of files for implicit dependencies of each language: +SET(CMAKE_DEPENDS_CHECK_CXX + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils/raspicam_cv_test.cpp" "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.o" + ) +SET(CMAKE_CXX_COMPILER_ID "GNU") + +# Targets to which this target links. +SET(CMAKE_TARGET_LINKED_INFO_FILES + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/DependInfo.cmake" + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam_cv.dir/DependInfo.cmake" + ) + +# The include file search paths: +SET(CMAKE_C_TARGET_INCLUDE_PATH + "../dependencies" + "../dependencies/mmal" + "../dependencies/vcos" + "/usr/local/include/opencv" + "/usr/local/include" + "../src" + ) +SET(CMAKE_CXX_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_Fortran_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_ASM_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/build.make b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/build.make new file mode 100644 index 0000000..23fa3ab --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/build.make @@ -0,0 +1,124 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E remove -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build + +# Include any dependencies generated for this target. +include utils/CMakeFiles/raspicam_cv_test.dir/depend.make + +# Include the progress variables for this target. +include utils/CMakeFiles/raspicam_cv_test.dir/progress.make + +# Include the compile flags for this target's objects. +include utils/CMakeFiles/raspicam_cv_test.dir/flags.make + +utils/CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.o: utils/CMakeFiles/raspicam_cv_test.dir/flags.make +utils/CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.o: ../utils/raspicam_cv_test.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles $(CMAKE_PROGRESS_1) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object utils/CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.o" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.o -c /home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils/raspicam_cv_test.cpp + +utils/CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.i" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils/raspicam_cv_test.cpp > CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.i + +utils/CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.s" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils/raspicam_cv_test.cpp -o CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.s + +utils/CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.o.requires: +.PHONY : utils/CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.o.requires + +utils/CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.o.provides: utils/CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.o.requires + $(MAKE) -f utils/CMakeFiles/raspicam_cv_test.dir/build.make utils/CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.o.provides.build +.PHONY : utils/CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.o.provides + +utils/CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.o.provides.build: utils/CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.o + +# Object files for target raspicam_cv_test +raspicam_cv_test_OBJECTS = \ +"CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.o" + +# External object files for target raspicam_cv_test +raspicam_cv_test_EXTERNAL_OBJECTS = + +utils/raspicam_cv_test: utils/CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.o +utils/raspicam_cv_test: utils/CMakeFiles/raspicam_cv_test.dir/build.make +utils/raspicam_cv_test: src/libraspicam.so.0.1.2 +utils/raspicam_cv_test: src/libraspicam_cv.so +utils/raspicam_cv_test: /opt/vc/lib/libmmal_core.so +utils/raspicam_cv_test: /opt/vc/lib/libmmal_util.so +utils/raspicam_cv_test: /opt/vc/lib/libmmal.so +utils/raspicam_cv_test: /usr/local/lib/libopencv_videostab.so.3.0.0 +utils/raspicam_cv_test: /usr/local/lib/libopencv_superres.so.3.0.0 +utils/raspicam_cv_test: /usr/local/lib/libopencv_stitching.so.3.0.0 +utils/raspicam_cv_test: /usr/local/lib/libopencv_shape.so.3.0.0 +utils/raspicam_cv_test: /usr/local/lib/libopencv_video.so.3.0.0 +utils/raspicam_cv_test: /usr/local/lib/libopencv_photo.so.3.0.0 +utils/raspicam_cv_test: /usr/local/lib/libopencv_objdetect.so.3.0.0 +utils/raspicam_cv_test: /usr/local/lib/libopencv_calib3d.so.3.0.0 +utils/raspicam_cv_test: /usr/local/lib/libopencv_features2d.so.3.0.0 +utils/raspicam_cv_test: /usr/local/lib/libopencv_ml.so.3.0.0 +utils/raspicam_cv_test: /usr/local/lib/libopencv_highgui.so.3.0.0 +utils/raspicam_cv_test: /usr/local/lib/libopencv_videoio.so.3.0.0 +utils/raspicam_cv_test: /usr/local/lib/libopencv_imgcodecs.so.3.0.0 +utils/raspicam_cv_test: /usr/local/lib/libopencv_imgproc.so.3.0.0 +utils/raspicam_cv_test: /usr/local/lib/libopencv_flann.so.3.0.0 +utils/raspicam_cv_test: /usr/local/lib/libopencv_core.so.3.0.0 +utils/raspicam_cv_test: /usr/local/lib/libopencv_hal.a +utils/raspicam_cv_test: utils/CMakeFiles/raspicam_cv_test.dir/link.txt + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --red --bold "Linking CXX executable raspicam_cv_test" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/raspicam_cv_test.dir/link.txt --verbose=$(VERBOSE) + +# Rule to build all files generated by this target. +utils/CMakeFiles/raspicam_cv_test.dir/build: utils/raspicam_cv_test +.PHONY : utils/CMakeFiles/raspicam_cv_test.dir/build + +utils/CMakeFiles/raspicam_cv_test.dir/requires: utils/CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.o.requires +.PHONY : utils/CMakeFiles/raspicam_cv_test.dir/requires + +utils/CMakeFiles/raspicam_cv_test.dir/clean: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && $(CMAKE_COMMAND) -P CMakeFiles/raspicam_cv_test.dir/cmake_clean.cmake +.PHONY : utils/CMakeFiles/raspicam_cv_test.dir/clean + +utils/CMakeFiles/raspicam_cv_test.dir/depend: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /home/ubuntu/Nomad/external_src/raspicam-0.1.3 /home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : utils/CMakeFiles/raspicam_cv_test.dir/depend + diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/cmake_clean.cmake b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/cmake_clean.cmake new file mode 100644 index 0000000..b3dac4d --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/cmake_clean.cmake @@ -0,0 +1,10 @@ +FILE(REMOVE_RECURSE + "CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.o" + "raspicam_cv_test.pdb" + "raspicam_cv_test" +) + +# Per-language clean rules from dependency scanning. +FOREACH(lang CXX) + INCLUDE(CMakeFiles/raspicam_cv_test.dir/cmake_clean_${lang}.cmake OPTIONAL) +ENDFOREACH(lang) diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/depend.make b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/depend.make new file mode 100644 index 0000000..e21c676 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/depend.make @@ -0,0 +1,2 @@ +# Empty dependencies file for raspicam_cv_test. +# This may be replaced when dependencies are built. diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/flags.make b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/flags.make new file mode 100644 index 0000000..1b59b72 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/flags.make @@ -0,0 +1,8 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# compile CXX with /usr/bin/c++ +CXX_FLAGS = -std=c++0x -Wl,--no-as-needed -Wall -ffunction-sections -fomit-frame-pointer -O2 -ffast-math -DNDEBUG -lpthread -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/dependencies -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/dependencies/mmal -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/dependencies/vcos -I/usr/local/include/opencv -I/usr/local/include -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/src + +CXX_DEFINES = + diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/link.txt b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/link.txt new file mode 100644 index 0000000..5e6bb08 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/link.txt @@ -0,0 +1 @@ +/usr/bin/c++ -std=c++0x -Wl,--no-as-needed -Wall -ffunction-sections -fomit-frame-pointer -O2 -ffast-math -DNDEBUG -lpthread CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.o -o raspicam_cv_test -rdynamic ../src/libraspicam.so.0.1.2 ../src/libraspicam_cv.so /opt/vc/lib/libmmal_core.so /opt/vc/lib/libmmal_util.so /opt/vc/lib/libmmal.so /usr/local/lib/libopencv_videostab.so.3.0.0 /usr/local/lib/libopencv_superres.so.3.0.0 /usr/local/lib/libopencv_stitching.so.3.0.0 /usr/local/lib/libopencv_shape.so.3.0.0 /usr/local/lib/libopencv_video.so.3.0.0 /usr/local/lib/libopencv_photo.so.3.0.0 /usr/local/lib/libopencv_objdetect.so.3.0.0 /usr/local/lib/libopencv_calib3d.so.3.0.0 /usr/local/lib/libopencv_features2d.so.3.0.0 /usr/local/lib/libopencv_ml.so.3.0.0 /usr/local/lib/libopencv_highgui.so.3.0.0 /usr/local/lib/libopencv_videoio.so.3.0.0 /usr/local/lib/libopencv_imgcodecs.so.3.0.0 /usr/local/lib/libopencv_imgproc.so.3.0.0 /usr/local/lib/libopencv_flann.so.3.0.0 /usr/local/lib/libopencv_core.so.3.0.0 /usr/local/lib/libopencv_hal.a -ldl -lm -lpthread -lrt -Wl,-rpath,/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src:/opt/vc/lib:/usr/local/lib: diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/progress.make b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/progress.make new file mode 100644 index 0000000..153b0f2 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_cv_test.dir/progress.make @@ -0,0 +1,2 @@ +CMAKE_PROGRESS_1 = 9 + diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/DependInfo.cmake b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/DependInfo.cmake new file mode 100644 index 0000000..79de009 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/DependInfo.cmake @@ -0,0 +1,27 @@ +# The set of languages for which implicit dependencies are needed: +SET(CMAKE_DEPENDS_LANGUAGES + "CXX" + ) +# The set of files for implicit dependencies of each language: +SET(CMAKE_DEPENDS_CHECK_CXX + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils/raspicam_still_test.cpp" "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.o" + ) +SET(CMAKE_CXX_COMPILER_ID "GNU") + +# Targets to which this target links. +SET(CMAKE_TARGET_LINKED_INFO_FILES + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/DependInfo.cmake" + ) + +# The include file search paths: +SET(CMAKE_C_TARGET_INCLUDE_PATH + "../dependencies" + "../dependencies/mmal" + "../dependencies/vcos" + "/usr/local/include/opencv" + "/usr/local/include" + "../src" + ) +SET(CMAKE_CXX_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_Fortran_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_ASM_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/build.make b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/build.make new file mode 100644 index 0000000..45975a5 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/build.make @@ -0,0 +1,106 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E remove -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build + +# Include any dependencies generated for this target. +include utils/CMakeFiles/raspicam_still_test.dir/depend.make + +# Include the progress variables for this target. +include utils/CMakeFiles/raspicam_still_test.dir/progress.make + +# Include the compile flags for this target's objects. +include utils/CMakeFiles/raspicam_still_test.dir/flags.make + +utils/CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.o: utils/CMakeFiles/raspicam_still_test.dir/flags.make +utils/CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.o: ../utils/raspicam_still_test.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles $(CMAKE_PROGRESS_1) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object utils/CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.o" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.o -c /home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils/raspicam_still_test.cpp + +utils/CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.i" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils/raspicam_still_test.cpp > CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.i + +utils/CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.s" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils/raspicam_still_test.cpp -o CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.s + +utils/CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.o.requires: +.PHONY : utils/CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.o.requires + +utils/CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.o.provides: utils/CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.o.requires + $(MAKE) -f utils/CMakeFiles/raspicam_still_test.dir/build.make utils/CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.o.provides.build +.PHONY : utils/CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.o.provides + +utils/CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.o.provides.build: utils/CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.o + +# Object files for target raspicam_still_test +raspicam_still_test_OBJECTS = \ +"CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.o" + +# External object files for target raspicam_still_test +raspicam_still_test_EXTERNAL_OBJECTS = + +utils/raspicam_still_test: utils/CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.o +utils/raspicam_still_test: utils/CMakeFiles/raspicam_still_test.dir/build.make +utils/raspicam_still_test: src/libraspicam.so.0.1.2 +utils/raspicam_still_test: /opt/vc/lib/libmmal_core.so +utils/raspicam_still_test: /opt/vc/lib/libmmal_util.so +utils/raspicam_still_test: /opt/vc/lib/libmmal.so +utils/raspicam_still_test: utils/CMakeFiles/raspicam_still_test.dir/link.txt + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --red --bold "Linking CXX executable raspicam_still_test" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/raspicam_still_test.dir/link.txt --verbose=$(VERBOSE) + +# Rule to build all files generated by this target. +utils/CMakeFiles/raspicam_still_test.dir/build: utils/raspicam_still_test +.PHONY : utils/CMakeFiles/raspicam_still_test.dir/build + +utils/CMakeFiles/raspicam_still_test.dir/requires: utils/CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.o.requires +.PHONY : utils/CMakeFiles/raspicam_still_test.dir/requires + +utils/CMakeFiles/raspicam_still_test.dir/clean: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && $(CMAKE_COMMAND) -P CMakeFiles/raspicam_still_test.dir/cmake_clean.cmake +.PHONY : utils/CMakeFiles/raspicam_still_test.dir/clean + +utils/CMakeFiles/raspicam_still_test.dir/depend: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /home/ubuntu/Nomad/external_src/raspicam-0.1.3 /home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : utils/CMakeFiles/raspicam_still_test.dir/depend + diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/cmake_clean.cmake b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/cmake_clean.cmake new file mode 100644 index 0000000..c9a2551 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/cmake_clean.cmake @@ -0,0 +1,10 @@ +FILE(REMOVE_RECURSE + "CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.o" + "raspicam_still_test.pdb" + "raspicam_still_test" +) + +# Per-language clean rules from dependency scanning. +FOREACH(lang CXX) + INCLUDE(CMakeFiles/raspicam_still_test.dir/cmake_clean_${lang}.cmake OPTIONAL) +ENDFOREACH(lang) diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/depend.make b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/depend.make new file mode 100644 index 0000000..8f85649 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/depend.make @@ -0,0 +1,2 @@ +# Empty dependencies file for raspicam_still_test. +# This may be replaced when dependencies are built. diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/flags.make b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/flags.make new file mode 100644 index 0000000..1b59b72 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/flags.make @@ -0,0 +1,8 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# compile CXX with /usr/bin/c++ +CXX_FLAGS = -std=c++0x -Wl,--no-as-needed -Wall -ffunction-sections -fomit-frame-pointer -O2 -ffast-math -DNDEBUG -lpthread -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/dependencies -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/dependencies/mmal -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/dependencies/vcos -I/usr/local/include/opencv -I/usr/local/include -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/src + +CXX_DEFINES = + diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/link.txt b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/link.txt new file mode 100644 index 0000000..9884f02 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/link.txt @@ -0,0 +1 @@ +/usr/bin/c++ -std=c++0x -Wl,--no-as-needed -Wall -ffunction-sections -fomit-frame-pointer -O2 -ffast-math -DNDEBUG -lpthread CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.o -o raspicam_still_test -rdynamic ../src/libraspicam.so.0.1.2 /opt/vc/lib/libmmal_core.so /opt/vc/lib/libmmal_util.so /opt/vc/lib/libmmal.so -Wl,-rpath,/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src:/opt/vc/lib: diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/progress.make b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/progress.make new file mode 100644 index 0000000..d61796b --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_still_test.dir/progress.make @@ -0,0 +1,2 @@ +CMAKE_PROGRESS_1 = 10 + diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/DependInfo.cmake b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/DependInfo.cmake new file mode 100644 index 0000000..7922c37 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/DependInfo.cmake @@ -0,0 +1,27 @@ +# The set of languages for which implicit dependencies are needed: +SET(CMAKE_DEPENDS_LANGUAGES + "CXX" + ) +# The set of files for implicit dependencies of each language: +SET(CMAKE_DEPENDS_CHECK_CXX + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils/raspicam_test.cpp" "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/raspicam_test.cpp.o" + ) +SET(CMAKE_CXX_COMPILER_ID "GNU") + +# Targets to which this target links. +SET(CMAKE_TARGET_LINKED_INFO_FILES + "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src/CMakeFiles/raspicam.dir/DependInfo.cmake" + ) + +# The include file search paths: +SET(CMAKE_C_TARGET_INCLUDE_PATH + "../dependencies" + "../dependencies/mmal" + "../dependencies/vcos" + "/usr/local/include/opencv" + "/usr/local/include" + "../src" + ) +SET(CMAKE_CXX_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_Fortran_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_ASM_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/build.make b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/build.make new file mode 100644 index 0000000..97c77a0 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/build.make @@ -0,0 +1,106 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E remove -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build + +# Include any dependencies generated for this target. +include utils/CMakeFiles/raspicam_test.dir/depend.make + +# Include the progress variables for this target. +include utils/CMakeFiles/raspicam_test.dir/progress.make + +# Include the compile flags for this target's objects. +include utils/CMakeFiles/raspicam_test.dir/flags.make + +utils/CMakeFiles/raspicam_test.dir/raspicam_test.cpp.o: utils/CMakeFiles/raspicam_test.dir/flags.make +utils/CMakeFiles/raspicam_test.dir/raspicam_test.cpp.o: ../utils/raspicam_test.cpp + $(CMAKE_COMMAND) -E cmake_progress_report /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles $(CMAKE_PROGRESS_1) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building CXX object utils/CMakeFiles/raspicam_test.dir/raspicam_test.cpp.o" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -o CMakeFiles/raspicam_test.dir/raspicam_test.cpp.o -c /home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils/raspicam_test.cpp + +utils/CMakeFiles/raspicam_test.dir/raspicam_test.cpp.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/raspicam_test.dir/raspicam_test.cpp.i" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -E /home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils/raspicam_test.cpp > CMakeFiles/raspicam_test.dir/raspicam_test.cpp.i + +utils/CMakeFiles/raspicam_test.dir/raspicam_test.cpp.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/raspicam_test.dir/raspicam_test.cpp.s" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && /usr/bin/c++ $(CXX_DEFINES) $(CXX_FLAGS) -S /home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils/raspicam_test.cpp -o CMakeFiles/raspicam_test.dir/raspicam_test.cpp.s + +utils/CMakeFiles/raspicam_test.dir/raspicam_test.cpp.o.requires: +.PHONY : utils/CMakeFiles/raspicam_test.dir/raspicam_test.cpp.o.requires + +utils/CMakeFiles/raspicam_test.dir/raspicam_test.cpp.o.provides: utils/CMakeFiles/raspicam_test.dir/raspicam_test.cpp.o.requires + $(MAKE) -f utils/CMakeFiles/raspicam_test.dir/build.make utils/CMakeFiles/raspicam_test.dir/raspicam_test.cpp.o.provides.build +.PHONY : utils/CMakeFiles/raspicam_test.dir/raspicam_test.cpp.o.provides + +utils/CMakeFiles/raspicam_test.dir/raspicam_test.cpp.o.provides.build: utils/CMakeFiles/raspicam_test.dir/raspicam_test.cpp.o + +# Object files for target raspicam_test +raspicam_test_OBJECTS = \ +"CMakeFiles/raspicam_test.dir/raspicam_test.cpp.o" + +# External object files for target raspicam_test +raspicam_test_EXTERNAL_OBJECTS = + +utils/raspicam_test: utils/CMakeFiles/raspicam_test.dir/raspicam_test.cpp.o +utils/raspicam_test: utils/CMakeFiles/raspicam_test.dir/build.make +utils/raspicam_test: src/libraspicam.so.0.1.2 +utils/raspicam_test: /opt/vc/lib/libmmal_core.so +utils/raspicam_test: /opt/vc/lib/libmmal_util.so +utils/raspicam_test: /opt/vc/lib/libmmal.so +utils/raspicam_test: utils/CMakeFiles/raspicam_test.dir/link.txt + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --red --bold "Linking CXX executable raspicam_test" + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/raspicam_test.dir/link.txt --verbose=$(VERBOSE) + +# Rule to build all files generated by this target. +utils/CMakeFiles/raspicam_test.dir/build: utils/raspicam_test +.PHONY : utils/CMakeFiles/raspicam_test.dir/build + +utils/CMakeFiles/raspicam_test.dir/requires: utils/CMakeFiles/raspicam_test.dir/raspicam_test.cpp.o.requires +.PHONY : utils/CMakeFiles/raspicam_test.dir/requires + +utils/CMakeFiles/raspicam_test.dir/clean: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils && $(CMAKE_COMMAND) -P CMakeFiles/raspicam_test.dir/cmake_clean.cmake +.PHONY : utils/CMakeFiles/raspicam_test.dir/clean + +utils/CMakeFiles/raspicam_test.dir/depend: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /home/ubuntu/Nomad/external_src/raspicam-0.1.3 /home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : utils/CMakeFiles/raspicam_test.dir/depend + diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/cmake_clean.cmake b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/cmake_clean.cmake new file mode 100644 index 0000000..bf9094c --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/cmake_clean.cmake @@ -0,0 +1,10 @@ +FILE(REMOVE_RECURSE + "CMakeFiles/raspicam_test.dir/raspicam_test.cpp.o" + "raspicam_test.pdb" + "raspicam_test" +) + +# Per-language clean rules from dependency scanning. +FOREACH(lang CXX) + INCLUDE(CMakeFiles/raspicam_test.dir/cmake_clean_${lang}.cmake OPTIONAL) +ENDFOREACH(lang) diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/depend.make b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/depend.make new file mode 100644 index 0000000..cc48ce0 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/depend.make @@ -0,0 +1,2 @@ +# Empty dependencies file for raspicam_test. +# This may be replaced when dependencies are built. diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/flags.make b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/flags.make new file mode 100644 index 0000000..1b59b72 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/flags.make @@ -0,0 +1,8 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# compile CXX with /usr/bin/c++ +CXX_FLAGS = -std=c++0x -Wl,--no-as-needed -Wall -ffunction-sections -fomit-frame-pointer -O2 -ffast-math -DNDEBUG -lpthread -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/dependencies -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/dependencies/mmal -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/dependencies/vcos -I/usr/local/include/opencv -I/usr/local/include -I/home/ubuntu/Nomad/external_src/raspicam-0.1.3/src + +CXX_DEFINES = + diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/link.txt b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/link.txt new file mode 100644 index 0000000..52b1d53 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/link.txt @@ -0,0 +1 @@ +/usr/bin/c++ -std=c++0x -Wl,--no-as-needed -Wall -ffunction-sections -fomit-frame-pointer -O2 -ffast-math -DNDEBUG -lpthread CMakeFiles/raspicam_test.dir/raspicam_test.cpp.o -o raspicam_test -rdynamic ../src/libraspicam.so.0.1.2 /opt/vc/lib/libmmal_core.so /opt/vc/lib/libmmal_util.so /opt/vc/lib/libmmal.so -Wl,-rpath,/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/src:/opt/vc/lib: diff --git a/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/progress.make b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/progress.make new file mode 100644 index 0000000..27952ed --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/CMakeFiles/raspicam_test.dir/progress.make @@ -0,0 +1,2 @@ +CMAKE_PROGRESS_1 = 11 + diff --git a/external_src/raspicam-0.1.3/build/utils/Makefile b/external_src/raspicam-0.1.3/build/utils/Makefile new file mode 100644 index 0000000..0bdf7c4 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/Makefile @@ -0,0 +1,335 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E remove -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running interactive CMake command-line interface..." + /usr/bin/cmake -i . +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache +.PHONY : edit_cache/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /usr/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /usr/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: install/local +.PHONY : install/local/fast + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: install/strip +.PHONY : install/strip/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\" \"main\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components +.PHONY : list_install_components/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /usr/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache +.PHONY : rebuild_cache/fast + +# The main all target +all: cmake_check_build_system + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils/CMakeFiles/progress.marks + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f CMakeFiles/Makefile2 utils/all + $(CMAKE_COMMAND) -E cmake_progress_start /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f CMakeFiles/Makefile2 utils/clean +.PHONY : clean + +# The main clean target +clean/fast: clean +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f CMakeFiles/Makefile2 utils/preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f CMakeFiles/Makefile2 utils/preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +# Convenience name for target. +utils/CMakeFiles/raspicam_cv_still_test.dir/rule: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f CMakeFiles/Makefile2 utils/CMakeFiles/raspicam_cv_still_test.dir/rule +.PHONY : utils/CMakeFiles/raspicam_cv_still_test.dir/rule + +# Convenience name for target. +raspicam_cv_still_test: utils/CMakeFiles/raspicam_cv_still_test.dir/rule +.PHONY : raspicam_cv_still_test + +# fast build rule for target. +raspicam_cv_still_test/fast: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f utils/CMakeFiles/raspicam_cv_still_test.dir/build.make utils/CMakeFiles/raspicam_cv_still_test.dir/build +.PHONY : raspicam_cv_still_test/fast + +# Convenience name for target. +utils/CMakeFiles/raspicam_cv_test.dir/rule: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f CMakeFiles/Makefile2 utils/CMakeFiles/raspicam_cv_test.dir/rule +.PHONY : utils/CMakeFiles/raspicam_cv_test.dir/rule + +# Convenience name for target. +raspicam_cv_test: utils/CMakeFiles/raspicam_cv_test.dir/rule +.PHONY : raspicam_cv_test + +# fast build rule for target. +raspicam_cv_test/fast: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f utils/CMakeFiles/raspicam_cv_test.dir/build.make utils/CMakeFiles/raspicam_cv_test.dir/build +.PHONY : raspicam_cv_test/fast + +# Convenience name for target. +utils/CMakeFiles/raspicam_still_test.dir/rule: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f CMakeFiles/Makefile2 utils/CMakeFiles/raspicam_still_test.dir/rule +.PHONY : utils/CMakeFiles/raspicam_still_test.dir/rule + +# Convenience name for target. +raspicam_still_test: utils/CMakeFiles/raspicam_still_test.dir/rule +.PHONY : raspicam_still_test + +# fast build rule for target. +raspicam_still_test/fast: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f utils/CMakeFiles/raspicam_still_test.dir/build.make utils/CMakeFiles/raspicam_still_test.dir/build +.PHONY : raspicam_still_test/fast + +# Convenience name for target. +utils/CMakeFiles/raspicam_test.dir/rule: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f CMakeFiles/Makefile2 utils/CMakeFiles/raspicam_test.dir/rule +.PHONY : utils/CMakeFiles/raspicam_test.dir/rule + +# Convenience name for target. +raspicam_test: utils/CMakeFiles/raspicam_test.dir/rule +.PHONY : raspicam_test + +# fast build rule for target. +raspicam_test/fast: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f utils/CMakeFiles/raspicam_test.dir/build.make utils/CMakeFiles/raspicam_test.dir/build +.PHONY : raspicam_test/fast + +raspicam_cv_still_test.o: raspicam_cv_still_test.cpp.o +.PHONY : raspicam_cv_still_test.o + +# target to build an object file +raspicam_cv_still_test.cpp.o: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f utils/CMakeFiles/raspicam_cv_still_test.dir/build.make utils/CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.o +.PHONY : raspicam_cv_still_test.cpp.o + +raspicam_cv_still_test.i: raspicam_cv_still_test.cpp.i +.PHONY : raspicam_cv_still_test.i + +# target to preprocess a source file +raspicam_cv_still_test.cpp.i: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f utils/CMakeFiles/raspicam_cv_still_test.dir/build.make utils/CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.i +.PHONY : raspicam_cv_still_test.cpp.i + +raspicam_cv_still_test.s: raspicam_cv_still_test.cpp.s +.PHONY : raspicam_cv_still_test.s + +# target to generate assembly for a file +raspicam_cv_still_test.cpp.s: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f utils/CMakeFiles/raspicam_cv_still_test.dir/build.make utils/CMakeFiles/raspicam_cv_still_test.dir/raspicam_cv_still_test.cpp.s +.PHONY : raspicam_cv_still_test.cpp.s + +raspicam_cv_test.o: raspicam_cv_test.cpp.o +.PHONY : raspicam_cv_test.o + +# target to build an object file +raspicam_cv_test.cpp.o: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f utils/CMakeFiles/raspicam_cv_test.dir/build.make utils/CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.o +.PHONY : raspicam_cv_test.cpp.o + +raspicam_cv_test.i: raspicam_cv_test.cpp.i +.PHONY : raspicam_cv_test.i + +# target to preprocess a source file +raspicam_cv_test.cpp.i: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f utils/CMakeFiles/raspicam_cv_test.dir/build.make utils/CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.i +.PHONY : raspicam_cv_test.cpp.i + +raspicam_cv_test.s: raspicam_cv_test.cpp.s +.PHONY : raspicam_cv_test.s + +# target to generate assembly for a file +raspicam_cv_test.cpp.s: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f utils/CMakeFiles/raspicam_cv_test.dir/build.make utils/CMakeFiles/raspicam_cv_test.dir/raspicam_cv_test.cpp.s +.PHONY : raspicam_cv_test.cpp.s + +raspicam_still_test.o: raspicam_still_test.cpp.o +.PHONY : raspicam_still_test.o + +# target to build an object file +raspicam_still_test.cpp.o: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f utils/CMakeFiles/raspicam_still_test.dir/build.make utils/CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.o +.PHONY : raspicam_still_test.cpp.o + +raspicam_still_test.i: raspicam_still_test.cpp.i +.PHONY : raspicam_still_test.i + +# target to preprocess a source file +raspicam_still_test.cpp.i: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f utils/CMakeFiles/raspicam_still_test.dir/build.make utils/CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.i +.PHONY : raspicam_still_test.cpp.i + +raspicam_still_test.s: raspicam_still_test.cpp.s +.PHONY : raspicam_still_test.s + +# target to generate assembly for a file +raspicam_still_test.cpp.s: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f utils/CMakeFiles/raspicam_still_test.dir/build.make utils/CMakeFiles/raspicam_still_test.dir/raspicam_still_test.cpp.s +.PHONY : raspicam_still_test.cpp.s + +raspicam_test.o: raspicam_test.cpp.o +.PHONY : raspicam_test.o + +# target to build an object file +raspicam_test.cpp.o: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f utils/CMakeFiles/raspicam_test.dir/build.make utils/CMakeFiles/raspicam_test.dir/raspicam_test.cpp.o +.PHONY : raspicam_test.cpp.o + +raspicam_test.i: raspicam_test.cpp.i +.PHONY : raspicam_test.i + +# target to preprocess a source file +raspicam_test.cpp.i: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f utils/CMakeFiles/raspicam_test.dir/build.make utils/CMakeFiles/raspicam_test.dir/raspicam_test.cpp.i +.PHONY : raspicam_test.cpp.i + +raspicam_test.s: raspicam_test.cpp.s +.PHONY : raspicam_test.s + +# target to generate assembly for a file +raspicam_test.cpp.s: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(MAKE) -f utils/CMakeFiles/raspicam_test.dir/build.make utils/CMakeFiles/raspicam_test.dir/raspicam_test.cpp.s +.PHONY : raspicam_test.cpp.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... install" + @echo "... install/local" + @echo "... install/strip" + @echo "... list_install_components" + @echo "... raspicam_cv_still_test" + @echo "... raspicam_cv_test" + @echo "... raspicam_still_test" + @echo "... raspicam_test" + @echo "... rebuild_cache" + @echo "... raspicam_cv_still_test.o" + @echo "... raspicam_cv_still_test.i" + @echo "... raspicam_cv_still_test.s" + @echo "... raspicam_cv_test.o" + @echo "... raspicam_cv_test.i" + @echo "... raspicam_cv_test.s" + @echo "... raspicam_still_test.o" + @echo "... raspicam_still_test.i" + @echo "... raspicam_still_test.s" + @echo "... raspicam_test.o" + @echo "... raspicam_test.i" + @echo "... raspicam_test.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + cd /home/ubuntu/Nomad/external_src/raspicam-0.1.3/build && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/external_src/raspicam-0.1.3/build/utils/cmake_install.cmake b/external_src/raspicam-0.1.3/build/utils/cmake_install.cmake new file mode 100644 index 0000000..d04c5a1 --- /dev/null +++ b/external_src/raspicam-0.1.3/build/utils/cmake_install.cmake @@ -0,0 +1,106 @@ +# Install script for directory: /home/ubuntu/Nomad/external_src/raspicam-0.1.3/utils + +# Set the install prefix +IF(NOT DEFINED CMAKE_INSTALL_PREFIX) + SET(CMAKE_INSTALL_PREFIX "/usr/local") +ENDIF(NOT DEFINED CMAKE_INSTALL_PREFIX) +STRING(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +IF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + IF(BUILD_TYPE) + STRING(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + ELSE(BUILD_TYPE) + SET(CMAKE_INSTALL_CONFIG_NAME "Release") + ENDIF(BUILD_TYPE) + MESSAGE(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +ENDIF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + +# Set the component getting installed. +IF(NOT CMAKE_INSTALL_COMPONENT) + IF(COMPONENT) + MESSAGE(STATUS "Install component: \"${COMPONENT}\"") + SET(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + ELSE(COMPONENT) + SET(CMAKE_INSTALL_COMPONENT) + ENDIF(COMPONENT) +ENDIF(NOT CMAKE_INSTALL_COMPONENT) + +# Install shared libraries without execute permission? +IF(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) + SET(CMAKE_INSTALL_SO_NO_EXE "1") +ENDIF(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) + +IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified") + IF(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_test" AND + NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_test") + FILE(RPATH_CHECK + FILE "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_test" + RPATH "") + ENDIF() + FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/bin" TYPE EXECUTABLE FILES "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils/raspicam_test") + IF(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_test" AND + NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_test") + FILE(RPATH_REMOVE + FILE "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_test") + IF(CMAKE_INSTALL_DO_STRIP) + EXECUTE_PROCESS(COMMAND "/usr/bin/strip" "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_test") + ENDIF(CMAKE_INSTALL_DO_STRIP) + ENDIF() +ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified") + +IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified") + IF(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_still_test" AND + NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_still_test") + FILE(RPATH_CHECK + FILE "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_still_test" + RPATH "") + ENDIF() + FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/bin" TYPE EXECUTABLE FILES "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils/raspicam_still_test") + IF(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_still_test" AND + NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_still_test") + FILE(RPATH_REMOVE + FILE "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_still_test") + IF(CMAKE_INSTALL_DO_STRIP) + EXECUTE_PROCESS(COMMAND "/usr/bin/strip" "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_still_test") + ENDIF(CMAKE_INSTALL_DO_STRIP) + ENDIF() +ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified") + +IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified") + IF(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_cv_test" AND + NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_cv_test") + FILE(RPATH_CHECK + FILE "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_cv_test" + RPATH "") + ENDIF() + FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/bin" TYPE EXECUTABLE FILES "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils/raspicam_cv_test") + IF(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_cv_test" AND + NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_cv_test") + FILE(RPATH_REMOVE + FILE "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_cv_test") + IF(CMAKE_INSTALL_DO_STRIP) + EXECUTE_PROCESS(COMMAND "/usr/bin/strip" "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_cv_test") + ENDIF(CMAKE_INSTALL_DO_STRIP) + ENDIF() +ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified") + +IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified") + IF(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_cv_still_test" AND + NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_cv_still_test") + FILE(RPATH_CHECK + FILE "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_cv_still_test" + RPATH "") + ENDIF() + FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/bin" TYPE EXECUTABLE FILES "/home/ubuntu/Nomad/external_src/raspicam-0.1.3/build/utils/raspicam_cv_still_test") + IF(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_cv_still_test" AND + NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_cv_still_test") + FILE(RPATH_REMOVE + FILE "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_cv_still_test") + IF(CMAKE_INSTALL_DO_STRIP) + EXECUTE_PROCESS(COMMAND "/usr/bin/strip" "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/raspicam_cv_still_test") + ENDIF(CMAKE_INSTALL_DO_STRIP) + ENDIF() +ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified") + diff --git a/external_src/raspicam-0.1.3/cmake_uninstall.cmake.in b/external_src/raspicam-0.1.3/cmake_uninstall.cmake.in new file mode 100644 index 0000000..81482da --- /dev/null +++ b/external_src/raspicam-0.1.3/cmake_uninstall.cmake.in @@ -0,0 +1,28 @@ +# ----------------------------------------------- +# File that provides "make uninstall" target +# We use the file 'install_manifest.txt' +# ----------------------------------------------- +IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +STRING(REGEX REPLACE "\n" ";" files "${files}") +FOREACH(file ${files}) + MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") +# IF(EXISTS "$ENV{DESTDIR}${file}") +# EXEC_PROGRAM( +# "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" +# OUTPUT_VARIABLE rm_out +# RETURN_VALUE rm_retval +# ) + EXECUTE_PROCESS(COMMAND rm $ENV{DESTDIR}${file}) +# IF(NOT "${rm_retval}" STREQUAL 0) +# MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") +# ENDIF(NOT "${rm_retval}" STREQUAL 0) +# ELSE(EXISTS "$ENV{DESTDIR}${file}") +# MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") +# ENDIF(EXISTS "$ENV{DESTDIR}${file}") +ENDFOREACH(file) + + diff --git a/external_src/raspicam-0.1.3/config.cmake.in b/external_src/raspicam-0.1.3/config.cmake.in new file mode 100644 index 0000000..48aa39b --- /dev/null +++ b/external_src/raspicam-0.1.3/config.cmake.in @@ -0,0 +1,34 @@ +# =================================================================================== +# @PROJECT_NAME@ CMake configuration file +# +# ** File generated automatically, do not modify ** +# +# Usage from an external project: +# In your CMakeLists.txt, add these lines: +# +# FIND_PACKAGE(@PROJECT_NAME@ REQUIRED ) +# TARGET_LINK_LIBRARIES(MY_TARGET_NAME ${@PROJECT_NAME@_LIBS}) +# +# This file will define the following variables: +# - @PROJECT_NAME@_LIBS : The list of libraries to links against. +# - @PROJECT_NAME@_LIB_DIR : The directory where lib files are. Calling LINK_DIRECTORIES +# with this path is NOT needed. +# - @PROJECT_NAME@_VERSION : The version of this PROJECT_NAME build. Example: "1.2.0" +# - @PROJECT_NAME@_VERSION_MAJOR : Major version part of VERSION. Example: "1" +# - @PROJECT_NAME@_VERSION_MINOR : Minor version part of VERSION. Example: "2" +# - @PROJECT_NAME@_VERSION_PATCH : Patch version part of VERSION. Example: "0" +# +# =================================================================================== +INCLUDE_DIRECTORIES(@REQUIRED_INC_DIR@;@CMAKE_INSTALL_PREFIX@/include) +LINK_DIRECTORIES("@CMAKE_INSTALL_PREFIX@/lib") + +SET(@PROJECT_NAME@_LIBS @REQUIRED_LIBRARIES@ @PROJECT_NAME@@PROJECT_DLLVERSION@) +SET(@PROJECT_NAME@_FOUND "YES") + +SET(@PROJECT_NAME@_CV_FOUND "@PROJECT_CV_CREATED_FLAG@") +SET(@PROJECT_NAME@_CV_LIBS @REQUIRED_LIBRARIES@ @PROJECT_NAME@@PROJECT_DLLVERSION@ @OpenCV_LIBS@ @PROJECT_NAME@_cv@PROJECT_DLLVERSION@) + +SET(@PROJECT_NAME@_VERSION @PROJECT_VERSION@) +SET(@PROJECT_NAME@_VERSION_MAJOR @PROJECT_VERSION_MAJOR@) +SET(@PROJECT_NAME@_VERSION_MINOR @PROJECT_VERSION_MINOR@) +SET(@PROJECT_NAME@_VERSION_PATCH @PROJECT_VERSION_PATCH@) diff --git a/external_src/raspicam-0.1.3/dependencies/mmal/CMakeLists.txt b/external_src/raspicam-0.1.3/dependencies/mmal/CMakeLists.txt new file mode 100644 index 0000000..37ae757 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/CMakeLists.txt @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/client/CMakeLists.txt b/external_src/raspicam-0.1.3/dependencies/mmal/client/CMakeLists.txt new file mode 100644 index 0000000..58bdaed --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/client/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(brcmjpeg) diff --git a/external_src/raspicam-0.1.3/dependencies/mmal/client/brcmjpeg/CMakeLists.txt b/external_src/raspicam-0.1.3/dependencies/mmal/client/brcmjpeg/CMakeLists.txt new file mode 100644 index 0000000..342a182 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/client/brcmjpeg/CMakeLists.txt @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/client/brcmjpeg/brcmjpeg.c b/external_src/raspicam-0.1.3/dependencies/mmal/client/brcmjpeg/brcmjpeg.c new file mode 100644 index 0000000..1fc4220 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/client/brcmjpeg/brcmjpeg.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/client/brcmjpeg/brcmjpeg.h b/external_src/raspicam-0.1.3/dependencies/mmal/client/brcmjpeg/brcmjpeg.h new file mode 100644 index 0000000..d787e99 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/client/brcmjpeg/brcmjpeg.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/client/brcmjpeg/brcmjpeg_test.c b/external_src/raspicam-0.1.3/dependencies/mmal/client/brcmjpeg/brcmjpeg_test.c new file mode 100644 index 0000000..9e249b6 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/client/brcmjpeg/brcmjpeg_test.c @@ -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 +#include +#include +#include +#include +#include +#include + +#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 : process each file N times\n"); + fprintf(stderr, " -f : 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/external_src/raspicam-0.1.3/dependencies/mmal/components/CMakeLists.txt b/external_src/raspicam-0.1.3/dependencies/mmal/components/CMakeLists.txt new file mode 100644 index 0000000..d65fa37 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/components/CMakeLists.txt @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/components/aaf_audio_render.cpp b/external_src/raspicam-0.1.3/dependencies/mmal/components/aaf_audio_render.cpp new file mode 100644 index 0000000..32b5d6d --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/components/aaf_audio_render.cpp @@ -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 +#include + +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 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/external_src/raspicam-0.1.3/dependencies/mmal/components/aggregator.c b/external_src/raspicam-0.1.3/dependencies/mmal/components/aggregator.c new file mode 100644 index 0000000..fac4596 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/components/aggregator.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/components/android_media_codec.cpp b/external_src/raspicam-0.1.3/dependencies/mmal/components/android_media_codec.cpp new file mode 100644 index 0000000..8877a52 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/components/android_media_codec.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include + +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 &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 &msg) + { + (void)msg; + mNotificationRequested = false; + mmal_component_action_trigger(mComponent); + } + +private: + MMAL_COMPONENT_T *mComponent; + sp mActivityNotify; + bool mNotificationRequested; +}; + +typedef struct MMAL_COMPONENT_MODULE_T +{ + MMAL_STATUS_T status; /**< current status of the component */ + + sp codec; + sp ahandler; + sp alooper; + Vector > input_buffers; /**< list of buffers exported by mediacodec */ + Vector > 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 *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 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 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 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 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 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; + 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/external_src/raspicam-0.1.3/dependencies/mmal/components/artificial_camera.c b/external_src/raspicam-0.1.3/dependencies/mmal/components/artificial_camera.c new file mode 100644 index 0000000..e883f53 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/components/artificial_camera.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/components/avcodec_audio_decoder.c b/external_src/raspicam-0.1.3/dependencies/mmal/components/avcodec_audio_decoder.c new file mode 100644 index 0000000..20f6192 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/components/avcodec_audio_decoder.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/components/avcodec_video_decoder.c b/external_src/raspicam-0.1.3/dependencies/mmal/components/avcodec_video_decoder.c new file mode 100644 index 0000000..356c429 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/components/avcodec_video_decoder.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/components/clock.c b/external_src/raspicam-0.1.3/dependencies/mmal/components/clock.c new file mode 100644 index 0000000..d59f4e4 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/components/clock.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/components/container_reader.c b/external_src/raspicam-0.1.3/dependencies/mmal/components/container_reader.c new file mode 100644 index 0000000..b4e77da --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/components/container_reader.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/components/copy.c b/external_src/raspicam-0.1.3/dependencies/mmal/components/copy.c new file mode 100644 index 0000000..1bbd952 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/components/copy.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/components/null_sink.c b/external_src/raspicam-0.1.3/dependencies/mmal/components/null_sink.c new file mode 100644 index 0000000..78c7144 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/components/null_sink.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/components/passthrough.c b/external_src/raspicam-0.1.3/dependencies/mmal/components/passthrough.c new file mode 100644 index 0000000..e51277d --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/components/passthrough.c @@ -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 = ∈ + 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/external_src/raspicam-0.1.3/dependencies/mmal/components/scheduler.c b/external_src/raspicam-0.1.3/dependencies/mmal/components/scheduler.c new file mode 100644 index 0000000..753b46a --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/components/scheduler.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/components/sdl_audio_render.c b/external_src/raspicam-0.1.3/dependencies/mmal/components/sdl_audio_render.c new file mode 100644 index 0000000..43c2ff2 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/components/sdl_audio_render.c @@ -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 + +#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/external_src/raspicam-0.1.3/dependencies/mmal/components/sdl_video_render.c b/external_src/raspicam-0.1.3/dependencies/mmal/components/sdl_video_render.c new file mode 100644 index 0000000..6f95d96 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/components/sdl_video_render.c @@ -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 + +#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/external_src/raspicam-0.1.3/dependencies/mmal/components/spdif.c b/external_src/raspicam-0.1.3/dependencies/mmal/components/spdif.c new file mode 100644 index 0000000..d5747ee --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/components/spdif.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/components/splitter.c b/external_src/raspicam-0.1.3/dependencies/mmal/components/splitter.c new file mode 100644 index 0000000..7753a16 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/components/splitter.c @@ -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<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<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<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/external_src/raspicam-0.1.3/dependencies/mmal/core/CMakeLists.txt b/external_src/raspicam-0.1.3/dependencies/mmal/core/CMakeLists.txt new file mode 100644 index 0000000..388d493 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/core/CMakeLists.txt @@ -0,0 +1,24 @@ +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 + DESTINATION include/interface/mmal/core +) diff --git a/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_buffer.c b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_buffer.c new file mode 100644 index 0000000..3f83063 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_buffer.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_buffer_private.h b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_buffer_private.h new file mode 100644 index 0000000..d24be20 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_buffer_private.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_clock.c b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_clock.c new file mode 100644 index 0000000..23f3043 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_clock.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_clock_private.h b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_clock_private.h new file mode 100644 index 0000000..25ebc87 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_clock_private.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_component.c b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_component.c new file mode 100644 index 0000000..c621ca8 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_component.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_component_private.h b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_component_private.h new file mode 100644 index 0000000..26c7a7e --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_component_private.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_core_private.h b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_core_private.h new file mode 100644 index 0000000..8dc6cba --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_core_private.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_events.c b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_events.c new file mode 100644 index 0000000..80607f7 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_events.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_events_private.h b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_events_private.h new file mode 100644 index 0000000..00d7307 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_events_private.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_format.c b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_format.c new file mode 100644 index 0000000..7b8e25e --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_format.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_logging.c b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_logging.c new file mode 100644 index 0000000..e05bc92 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_logging.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_pool.c b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_pool.c new file mode 100644 index 0000000..1eac85f --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_pool.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_port.c b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_port.c new file mode 100644 index 0000000..d7b00c1 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_port.c @@ -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 + +#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 : "", 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), ""); + 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/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_port_clock.c b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_port_clock.c new file mode 100644 index 0000000..1eb7d10 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_port_clock.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_port_private.h b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_port_private.h new file mode 100644 index 0000000..1e538c5 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_port_private.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_queue.c b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_queue.c new file mode 100644 index 0000000..ad802cb --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/core/mmal_queue.c @@ -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 "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; +}; + +/** 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; + /* 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) +{ + if(!queue || !buffer) return; + + vcos_mutex_lock(&queue->lock); + queue->length++; + *queue->last = buffer; + buffer->next = 0; + queue->last = &buffer->next; + 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); + 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. */ +MMAL_BUFFER_HEADER_T *mmal_queue_get(MMAL_QUEUE_T *queue) +{ + MMAL_BUFFER_HEADER_T *buffer; + + if(!queue) return 0; + + vcos_mutex_lock(&queue->lock); + buffer = queue->first; + if(!buffer) + { + vcos_mutex_unlock(&queue->lock); + return 0; + } + + /* coverity[lock] This semaphore isn't being used as a mutex */ + vcos_semaphore_wait(&queue->semaphore); /* Will always succeed */ + + queue->first = buffer->next; + if(!queue->first) queue->last = &queue->first; + + queue->length--; + vcos_mutex_unlock(&queue->lock); + + return buffer; +} + +/** 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; + + vcos_semaphore_wait(&queue->semaphore); + vcos_semaphore_post(&queue->semaphore); + return mmal_queue_get(queue); +} + +MMAL_BUFFER_HEADER_T *mmal_queue_timedwait(MMAL_QUEUE_T *queue, VCOS_UNSIGNED timeout) +{ + int ret = 0; + if (!queue) + return NULL; + + ret = vcos_semaphore_wait_timeout(&queue->semaphore, timeout); + + if (ret != VCOS_SUCCESS) + return NULL; + + vcos_semaphore_post(&queue->semaphore); + return mmal_queue_get(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/external_src/raspicam-0.1.3/dependencies/mmal/mmal.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal.h new file mode 100644 index 0000000..e613f94 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal.h @@ -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 + * ... + * 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 *header; + * + * // 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/external_src/raspicam-0.1.3/dependencies/mmal/mmal_buffer.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_buffer.h new file mode 100644 index 0000000..7c91fce --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_buffer.h @@ -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 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 */ +/* @{ */ +/** Signals an interlaced video frame */ +#define MMAL_BUFFER_HEADER_VIDEO_FLAG_INTERLACED (1<<0) +/** Signals that the top field of the current interlaced frame should be displayed first */ +#define MMAL_BUFFER_HEADER_VIDEO_FLAG_TOP_FIELD_FIRST (1<<2) +/** Signals that the buffer should be displayed on external display if attached. */ +#define MMAL_BUFFER_HEADER_VIDEO_FLAG_DISPLAY_EXTERNAL (1<<3) +/** Signals that contents of the buffer requires copy protection. */ +#define MMAL_BUFFER_HEADER_VIDEO_FLAG_PROTECTED (1<<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/external_src/raspicam-0.1.3/dependencies/mmal/mmal_clock.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_clock.h new file mode 100644 index 0000000..e12509d --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_clock.h @@ -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 "vcos/vcos.h" +#include "mmal_types.h" +#include "mmal_common.h" +#include +/** \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 */ +static_assert(!(sizeof(MMAL_CLOCK_EVENT_T) & 0x7),"mmal error"); + +#define MMAL_CLOCK_EVENT_INIT(id) { id, MMAL_CLOCK_EVENT_MAGIC, NULL, 0, {0}, 0 } + +#endif /* MMAL_CLOCK_H */ diff --git a/external_src/raspicam-0.1.3/dependencies/mmal/mmal_common.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_common.h new file mode 100644 index 0000000..2482dd1 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_common.h @@ -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 +#include +#include +#include + +#include + +/* 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/external_src/raspicam-0.1.3/dependencies/mmal/mmal_component.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_component.h new file mode 100644 index 0000000..6c9d104 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_component.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/mmal_encodings.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_encodings.h new file mode 100644 index 0000000..5421a6d --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_encodings.h @@ -0,0 +1,208 @@ +/* +Copyright (c) 2012, Broadcom Europe Ltd +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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_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_RGBA MMAL_FOURCC('R','G','B','A') +#define MMAL_ENCODING_ABGR MMAL_FOURCC('A','B','G','R') +#define MMAL_ENCODING_BGRA MMAL_FOURCC('B','G','R','A') +#define MMAL_ENCODING_RGB16 MMAL_FOURCC('R','G','B','2') +#define MMAL_ENCODING_RGB24 MMAL_FOURCC('R','G','B','3') +#define MMAL_ENCODING_RGB32 MMAL_FOURCC('R','G','B','4') +#define MMAL_ENCODING_BGR16 MMAL_FOURCC('B','G','R','2') +#define MMAL_ENCODING_BGR24 MMAL_FOURCC('B','G','R','3') +#define MMAL_ENCODING_BGR32 MMAL_FOURCC('B','G','R','4') + +/** 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') + +/** 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/external_src/raspicam-0.1.3/dependencies/mmal/mmal_events.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_events.h new file mode 100644 index 0000000..94ccd56 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_events.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/mmal_format.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_format.h new file mode 100644 index 0000000..78c0844 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_format.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/mmal_logging.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_logging.h new file mode 100644 index 0000000..2307ab3 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_logging.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/mmal_metadata.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_metadata.h new file mode 100644 index 0000000..5d21dd0 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_metadata.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters.h new file mode 100644 index 0000000..67ffbda --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_audio.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_audio.h new file mode 100644 index 0000000..36625f6 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_audio.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_camera.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_camera.h new file mode 100644 index 0000000..7e550a7 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_camera.h @@ -0,0 +1,755 @@ +/* +Copyright (c) 2012, Broadcom Europe Ltd +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 */ +}; + +/** 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 + +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; +} 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; + +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; + +#endif /* MMAL_PARAMETERS_CAMERA_H */ diff --git a/external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_clock.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_clock.h new file mode 100644 index 0000000..9f798a1 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_clock.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_common.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_common.h new file mode 100644 index 0000000..28c3118 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_common.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_video.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_video.h new file mode 100644 index 0000000..16d8fa2 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_parameters_video.h @@ -0,0 +1,486 @@ +/* +Copyright (c) 2012, Broadcom Europe Ltd +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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. */ +}; + +/** 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 inital 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; + +#endif diff --git a/external_src/raspicam-0.1.3/dependencies/mmal/mmal_pool.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_pool.h new file mode 100644 index 0000000..4df5853 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_pool.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/mmal_port.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_port.h new file mode 100644 index 0000000..982c45f --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_port.h @@ -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: + *

+ * + * @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/external_src/raspicam-0.1.3/dependencies/mmal/mmal_queue.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_queue.h new file mode 100644 index 0000000..ce53a26 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_queue.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/mmal_types.h b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_types.h new file mode 100644 index 0000000..741f742 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/mmal_types.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/CMakeLists.txt b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/CMakeLists.txt new file mode 100644 index 0000000..68d9832 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/CMakeLists.txt @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx.h b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx.h new file mode 100644 index 0000000..d58971a --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx.h @@ -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 +#include + +/* 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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_buffer.c b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_buffer.c new file mode 100644 index 0000000..ef78baa --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_buffer.c @@ -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 + +/*****************************************************************************/ +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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_buffer.h b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_buffer.h new file mode 100644 index 0000000..425f7ef --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_buffer.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_commands.c b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_commands.c new file mode 100644 index 0000000..dd395d4 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_commands.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_commands.h b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_commands.h new file mode 100644 index 0000000..976b598 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_commands.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_core.c b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_core.c new file mode 100644 index 0000000..da66b0b --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_core.c @@ -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 +#include +#include +#include + +#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 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 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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_logging.c b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_logging.c new file mode 100644 index 0000000..3c2f70d --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_logging.c @@ -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 unkown" + }; + + 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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_logging.h b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_logging.h new file mode 100644 index 0000000..eb583ab --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_logging.h @@ -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 + +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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_marks.c b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_marks.c new file mode 100644 index 0000000..a645af6 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_marks.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_marks.h b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_marks.h new file mode 100644 index 0000000..f543396 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_marks.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_parameters.c b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_parameters.c new file mode 100644 index 0000000..a91b68c --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_parameters.c @@ -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 +#include +#include + +#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 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(¶m->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(¶m->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(¶m->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(¶m->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(¶m->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, ¶m->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, ¶m->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 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 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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_parameters.h b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_parameters.h new file mode 100644 index 0000000..5c58c86 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_parameters.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_registry.c b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_registry.c new file mode 100644 index 0000000..059ed6b --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_registry.c @@ -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 + +#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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_registry.h b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_registry.h new file mode 100644 index 0000000..3a7c7f5 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_registry.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_roles.c b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_roles.c new file mode 100644 index 0000000..17de66f --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_roles.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_roles.h b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_roles.h new file mode 100644 index 0000000..cd4828d --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_roles.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params.c b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params.c new file mode 100644 index 0000000..cb416cf --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params.c @@ -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 paramters 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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params.h b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params.h new file mode 100644 index 0000000..2520dfb --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_audio.c b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_audio.c new file mode 100644 index 0000000..2fb81bb --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_audio.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_camera.c b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_camera.c new file mode 100644 index 0000000..936eadc --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_camera.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_common.h b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_common.h new file mode 100644 index 0000000..f0f2f96 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_common.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_misc.c b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_misc.c new file mode 100644 index 0000000..e364033 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_misc.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_video.c b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_video.c new file mode 100644 index 0000000..f088296 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/openmaxil/mmalomx_util_params_video.c @@ -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 = 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 = 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 = 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 = 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/external_src/raspicam-0.1.3/dependencies/mmal/test/CMakeLists.txt b/external_src/raspicam-0.1.3/dependencies/mmal/test/CMakeLists.txt new file mode 100644 index 0000000..10ec113 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/test/CMakeLists.txt @@ -0,0 +1,26 @@ +SET( MMAL_TOP ../../.. ) +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) +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) +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) +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) +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) +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) +target_link_libraries(mmal_example_basic_2 -Wl,--whole-archive mmal_components -Wl,--no-whole-archive mmal_core) diff --git a/external_src/raspicam-0.1.3/dependencies/mmal/test/examples/example_basic_1.c b/external_src/raspicam-0.1.3/dependencies/mmal/test/examples/example_basic_1.c new file mode 100644 index 0000000..2265b37 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/test/examples/example_basic_1.c @@ -0,0 +1,238 @@ +/* +Copyright (c) 2012, Broadcom Europe Ltd +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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_default_components.h" +#include "interface/vcos/vcos.h" +#include + +#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; + } + + 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/external_src/raspicam-0.1.3/dependencies/mmal/test/examples/example_basic_2.c b/external_src/raspicam-0.1.3/dependencies/mmal/test/examples/example_basic_2.c new file mode 100644 index 0000000..aa02d8f --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/test/examples/example_basic_2.c @@ -0,0 +1,304 @@ +/* +Copyright (c) 2012, Broadcom Europe Ltd +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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_default_components.h" +#include "util/mmal_util_params.h" +#include "interface/vcos/vcos.h" +#include + +#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; + +/** 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; + } + + 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_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; !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) + 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", (char *)&buffer->cmd); + 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\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/external_src/raspicam-0.1.3/dependencies/mmal/test/examples/example_connections.c b/external_src/raspicam-0.1.3/dependencies/mmal/test/examples/example_connections.c new file mode 100644 index 0000000..463c11e --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/test/examples/example_connections.c @@ -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 "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 + +#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; + } + + 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/external_src/raspicam-0.1.3/dependencies/mmal/test/examples/example_graph.c b/external_src/raspicam-0.1.3/dependencies/mmal/test/examples/example_graph.c new file mode 100644 index 0000000..eba6838 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/test/examples/example_graph.c @@ -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. +*/ + +#include "mmal.h" +#include "util/mmal_graph.h" +#include "util/mmal_default_components.h" +#include "util/mmal_util_params.h" +#include + +#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; + } + + /* 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/external_src/raspicam-0.1.3/dependencies/mmal/util/CMakeLists.txt b/external_src/raspicam-0.1.3/dependencies/mmal/util/CMakeLists.txt new file mode 100644 index 0000000..b2a6858 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/CMakeLists.txt @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_component_wrapper.c b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_component_wrapper.c new file mode 100644 index 0000000..8548aca --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_component_wrapper.c @@ -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 + +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 + component->output_num) * 2; + 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, ¶m_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/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_component_wrapper.h b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_component_wrapper.h new file mode 100644 index 0000000..ce29ae6 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_component_wrapper.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_connection.c b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_connection.c new file mode 100644 index 0000000..2e88315 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_connection.c @@ -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. +*/ + +#include "mmal.h" +#include "util/mmal_util.h" +#include "util/mmal_connection.h" +#include "mmal_logging.h" +#include + +#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 an input port. Buffer is released. */ +static void mmal_connection_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); + + /* FIXME: 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 queued and not released, however this + * callback doesn't have access to the pool queue. */ + if (port->type == MMAL_PORT_TYPE_CLOCK && buffer->length) + { + LOG_ERROR("clock ports not supported"); + } + + /* 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; + MMAL_PARAM_UNUSED(port); + 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, ¶m.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, 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, 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/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_connection.h b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_connection.h new file mode 100644 index 0000000..d2a02b1 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_connection.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_default_components.h b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_default_components.h new file mode 100644 index 0000000..ddfd69d --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_default_components.h @@ -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 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" +#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" +#endif + +/** @} */ + +#endif /* MMAL_DEFAULT_COMPONENTS_H */ diff --git a/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_graph.c b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_graph.c new file mode 100644 index 0000000..b84d575 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_graph.c @@ -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 "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_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 || (port->type != MMAL_PORT_TYPE_INPUT && port->type != MMAL_PORT_TYPE_OUTPUT)) + return MMAL_EINVAL; + + list = port->type == MMAL_PORT_TYPE_INPUT ? private->input : private->output; + list_num = port->type == MMAL_PORT_TYPE_INPUT ? &private->input_num : &private->output_num; + 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) + { + LOG_ERROR("mmal_port_send_buffer failed (%i)", status); + mmal_queue_put_back(connection->pool->queue, buffer); + run_again = 0; + // FIXME: send error ? + 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; + + if (port->type != MMAL_PORT_TYPE_INPUT && port->type != MMAL_PORT_TYPE_OUTPUT) + return 0; + + list = port->type == MMAL_PORT_TYPE_INPUT ? graph->input : graph->output; + list_num = port->type == MMAL_PORT_TYPE_INPUT ? &graph->input_num : &graph->output_num; + 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; + unsigned int i, *list_num; + + if (port->type != MMAL_PORT_TYPE_INPUT && port->type != MMAL_PORT_TYPE_OUTPUT) + return 0; + + list = port->type == MMAL_PORT_TYPE_INPUT ? graph->input : graph->output; + list_num = port->type == MMAL_PORT_TYPE_INPUT ? &graph->input_num : &graph->output_num; + + for (i = 0; i < *list_num; i++) + if (list[i] == port) + break; + + if (i == *list_num) + return 0; + return port->type == MMAL_PORT_TYPE_INPUT ? component->input[i] : component->output[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); + + /* 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) + 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; + } + + 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; icomponent_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_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/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_graph.h b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_graph.h new file mode 100644 index 0000000..e6284ba --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_graph.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_il.c b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_il.c new file mode 100644 index 0000000..955e391 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_il.c @@ -0,0 +1,915 @@ +/* +Copyright (c) 2012, Broadcom Europe Ltd +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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_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 & 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) + { + omx->nFlags |= OMX_BUFFERFLAG_TIME_UNKNOWN; + omx->nTimeStamp = omx_ticks_from_s64(0); + } +} + +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; + mmal->pts = omx_ticks_to_s64(omx->nTimeStamp); + if (omx->nFlags & OMX_BUFFERFLAG_TIME_UNKNOWN) + mmal->pts = MMAL_TIME_UNKNOWN; + mmal->dts = MMAL_TIME_UNKNOWN; + 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 + 1 >= 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_MP4V, OMX_VIDEO_CodingMPEG4}, + {MMAL_ENCODING_MP2V, OMX_VIDEO_CodingMPEG2}, + {MMAL_ENCODING_MP1V, OMX_VIDEO_CodingMPEG2}, + {MMAL_ENCODING_H263, OMX_VIDEO_CodingH263}, + {MMAL_ENCODING_WMV3, OMX_VIDEO_CodingWMV}, + {MMAL_ENCODING_WMV2, OMX_VIDEO_CodingWMV}, + {MMAL_ENCODING_WMV1, OMX_VIDEO_CodingWMV}, + {MMAL_ENCODING_WVC1, 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_EGL_IMAGE, OMX_COLOR_FormatBRCMEGL}, + {MMAL_ENCODING_OPAQUE, OMX_COLOR_FormatBRCMOpaque}, + {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 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/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_il.h b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_il.h new file mode 100644 index 0000000..b13cbef --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_il.h @@ -0,0 +1,212 @@ +/* +Copyright (c) 2012, Broadcom Europe Ltd +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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_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/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_list.c b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_list.c new file mode 100644 index 0000000..6f45d78 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_list.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_list.h b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_list.h new file mode 100644 index 0000000..967cc7b --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_list.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_param_convert.c b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_param_convert.c new file mode 100644 index 0000000..f470210 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_param_convert.c @@ -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. +*/ +#include "mmal_param_convert.h" +#include +#include + +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; inum = 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/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_param_convert.h b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_param_convert.h new file mode 100644 index 0000000..1d653c2 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_param_convert.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util.c b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util.c new file mode 100644 index 0000000..8959e53 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util.c @@ -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. +*/ +#include "interface/mmal/mmal.h" +#include "mmal_encodings.h" +#include "mmal_util.h" +#include "mmal_logging.h" +#include +#include + +#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; +} pixel_pitch[] = +{ + {MMAL_ENCODING_I420, 1, 1}, + {MMAL_ENCODING_YV12, 1, 1}, + {MMAL_ENCODING_I422, 1, 1}, + {MMAL_ENCODING_NV21, 1, 1}, + {MMAL_ENCODING_NV12, 1, 1}, + {MMAL_ENCODING_ARGB, 4, 1}, + {MMAL_ENCODING_RGBA, 4, 1}, + {MMAL_ENCODING_RGB32, 4, 1}, + {MMAL_ENCODING_ABGR, 4, 1}, + {MMAL_ENCODING_BGRA, 4, 1}, + {MMAL_ENCODING_BGR32, 4, 1}, + {MMAL_ENCODING_RGB16, 2, 1}, + {MMAL_ENCODING_RGB24, 3, 1}, + {MMAL_ENCODING_BGR16, 2, 1}, + {MMAL_ENCODING_BGR24, 3, 1}, + + {MMAL_ENCODING_YUYV, 2, 1}, + {MMAL_ENCODING_YVYU, 2, 1}, + {MMAL_ENCODING_UYVY, 2, 1}, + {MMAL_ENCODING_VYUY, 2, 1}, + /* {MMAL_ENCODING_YUVUV128, 1, 1}, That's a special case which must not be included */ + {MMAL_ENCODING_UNKNOWN, 0, 0} +}; + +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 pixel_pitch[i].pitch_num * width / pixel_pitch[i].pitch_den; +} + +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; +} + diff --git a/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util.h b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util.h new file mode 100644 index 0000000..4e5c803 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util.h @@ -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. +*/ + +#ifndef MMAL_UTIL_H +#define MMAL_UTIL_H + +#include "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); + +/** 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); + + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif diff --git a/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util_params.c b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util_params.c new file mode 100644 index 0000000..6e24791 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util_params.c @@ -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, ¶m.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, ¶m.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, ¶m.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, ¶m.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, ¶m.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, ¶m.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, ¶m.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, ¶m.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, ¶m.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, ¶m.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, ¶m.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, ¶m.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, ¶m->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, ¶m->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, ®ion->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, ¶m.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(¶m, 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, ¶m.hdr); + if (ret == MMAL_SUCCESS) + *stats = param.stats; + return ret; +} diff --git a/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util_params.h b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util_params.h new file mode 100644 index 0000000..0b85e5b --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util_params.h @@ -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 "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/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util_rational.c b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util_rational.c new file mode 100644 index 0000000..288b27b --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util_rational.c @@ -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 +#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/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util_rational.h b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util_rational.h new file mode 100644 index 0000000..f459f51 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/util/mmal_util_rational.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/vc/CMakeLists.txt b/external_src/raspicam-0.1.3/dependencies/mmal/vc/CMakeLists.txt new file mode 100644 index 0000000..8065a48 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/vc/CMakeLists.txt @@ -0,0 +1,29 @@ +# MMAL can use VCSM to allow zero copy for ARM accessible buffers. +# This is not enabled by default right now because VCSM on RPI is still +# experimental. +# 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/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_api.c b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_api.c new file mode 100644 index 0000000..2e13418 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_api.c @@ -0,0 +1,1481 @@ +/* +Copyright (c) 2012, Broadcom Europe Ltd +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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; + + 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) + { + 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_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]; + MMAL_PARAM_UNUSED(module); + 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; + } + } + + 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_PARAM_UNUSED(port); + + if (port->format->encoding == MMAL_ENCODING_OPAQUE) + { + 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/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_api.h b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_api.h new file mode 100644 index 0000000..c80fb10 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_api.h @@ -0,0 +1,219 @@ +/* +Copyright (c) 2012, Broadcom Europe Ltd +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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; + +MMAL_STATUS_T mmal_vc_init(void); +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); + +/** 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/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_api_drm.c b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_api_drm.c new file mode 100644 index 0000000..a926a86 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_api_drm.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_api_drm.h b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_api_drm.h new file mode 100644 index 0000000..04688b6 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_api_drm.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_client.c b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_client.c new file mode 100644 index 0000000..b60544b --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_client.c @@ -0,0 +1,822 @@ +/* +Copyright (c) 2012, Broadcom Europe Ltd +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 + +#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) +{ + MMAL_STATUS_T status; + int i; + + status = vcos_semaphore_create(&waitpool->sem, VCOS_FUNCTION, + MAX_WAITERS); + if (status != MMAL_SUCCESS) + return status; + + for (i=0; iwaiters[i].inuse = 0; + status = vcos_semaphore_create(&waitpool->waiters[i].sem, + "mmal waiter", 0); + if (status != MMAL_SUCCESS) + break; + } + + if (status != MMAL_SUCCESS) + { + /* clean up */ + i--; + while (i>=0) + { + vcos_semaphore_delete(&waitpool->waiters[i].sem); + i--; + } + vcos_semaphore_delete(&waitpool->sem); + } + return status; +} + +static void destroy_waitpool(MMAL_WAITPOOL_T *waitpool) +{ + int i; + for (i=0; iwaiters[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; iwaitpool.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(void) +{ + 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(&mmal_vchiq_instance); + 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; +} + +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/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_client_priv.h b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_client_priv.h new file mode 100644 index 0000000..0fc3aaa --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_client_priv.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_dbglog.h b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_dbglog.h new file mode 100644 index 0000000..0008bc4 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_dbglog.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_diag.c b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_diag.c new file mode 100644 index 0000000..df39199 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_diag.c @@ -0,0 +1,843 @@ +/* +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 +#include +#include +#include +#ifdef __ANDROID__ +#include +#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_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 }, + { "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 \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; ievent_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; ientries[(start+i) & mask]; + char buf[256]; + int j; + uint32_t t = e->time; + printf("[%08u]: ", t-last_t); + last_t = t; + for (j=0; jevent_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; + +} + +/* 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 \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 2) + mmal_vc_host_log(argv[2]); + return 0; +} diff --git a/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_msgnames.c b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_msgnames.c new file mode 100644 index 0000000..ba53d45 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_msgnames.c @@ -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_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), + { 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/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_msgnames.h b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_msgnames.h new file mode 100644 index 0000000..12a97c7 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_msgnames.h @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_msgs.h b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_msgs.h new file mode 100644 index 0000000..440ee2d --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_msgs.h @@ -0,0 +1,525 @@ +/* +Copyright (c) 2012, Broadcom Europe Ltd +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 compatiblity */ +#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_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, /**< Unkown 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; + /* 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/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_opaque_alloc.c b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_opaque_alloc.c new file mode 100644 index 0000000..b5b5ba9 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_opaque_alloc.c @@ -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/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_opaque_alloc.h b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_opaque_alloc.h new file mode 100644 index 0000000..60a5e56 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_opaque_alloc.h @@ -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 +#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/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_shm.c b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_shm.c new file mode 100644 index 0000000..19222ca --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_shm.c @@ -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 "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; + + 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/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_shm.h b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_shm.h new file mode 100644 index 0000000..0aacb5b --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/mmal/vc/mmal_vc_shm.h @@ -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/external_src/raspicam-0.1.3/dependencies/vcos/CMakeLists.txt b/external_src/raspicam-0.1.3/dependencies/vcos/CMakeLists.txt new file mode 100644 index 0000000..23a8d72 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/CMakeLists.txt @@ -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/external_src/raspicam-0.1.3/dependencies/vcos/generic/CMakeLists.txt b/external_src/raspicam-0.1.3/dependencies/vcos/generic/CMakeLists.txt new file mode 100644 index 0000000..c09f376 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/CMakeLists.txt @@ -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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_abort.c b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_abort.c new file mode 100644 index 0000000..7da16ac --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_abort.c @@ -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 + + +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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_cmd.c b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_cmd.c new file mode 100644 index 0000000..3dfbdb3 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_cmd.c @@ -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; ¶m->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( ¶m, cmd_globals.cmd_entry ); + + if ( param.use_log ) + { + cmd_log_results( ¶m ); + 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( ¶m, "\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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_common.h b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_common.h new file mode 100644 index 0000000..93949e0 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_common.h @@ -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_MIN?(x)-1:VCOS_THREAD_PRI_MIN) +#else +/* bigger numbers are lower priority */ +#define VCOS_THREAD_PRI_MORE(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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_deprecated.h b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_deprecated.h new file mode 100644 index 0000000..0efa5c4 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_deprecated.h @@ -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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_blockpool.c b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_blockpool.c new file mode 100644 index 0000000..f4241a6 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_blockpool.c @@ -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 +#include +#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 noticable. */ + 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: + 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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_blockpool.h b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_blockpool.h new file mode 100644 index 0000000..4c387a3 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_blockpool.h @@ -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 "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 availabe 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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_event_flags.c b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_event_flags.c new file mode 100644 index 0000000..9a7c1bb --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_event_flags.c @@ -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 + +/** 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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_event_flags.h b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_event_flags.h new file mode 100644 index 0000000..de68388 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_event_flags.h @@ -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 "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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_named_sem.c b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_named_sem.c new file mode 100644 index 0000000..cf47962 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_named_sem.c @@ -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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_named_sem.h b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_named_sem.h new file mode 100644 index 0000000..725cffc --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_named_sem.h @@ -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 "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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_quickslow_mutex.h b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_quickslow_mutex.h new file mode 100644 index 0000000..1b2b5f9 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_quickslow_mutex.h @@ -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 "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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_reentrant_mtx.c b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_reentrant_mtx.c new file mode 100644 index 0000000..7258cbf --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_reentrant_mtx.c @@ -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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_reentrant_mtx.h b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_reentrant_mtx.h new file mode 100644 index 0000000..e8830ce --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_reentrant_mtx.h @@ -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 "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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_safe_string.c b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_safe_string.c new file mode 100644 index 0000000..4a02c22 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_safe_string.c @@ -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. +*/ + /***************************************************************************** + * Copyright 2012 Broadcom Corporation. All rights reserved. + * + * This program is the proprietary software of Broadcom Corporation and/or + * its licensors, and may only be used, duplicated, modified or distributed + * pursuant to the terms and conditions of a separate, written license + * agreement executed between you and Broadcom (an "Authorized License"). + * Except as set forth in an Authorized License, Broadcom grants no license + * (express or implied), right to use, or waiver of any kind with respect to + * the Software, and Broadcom expressly reserves all rights in and to the + * Software and all intellectual property rights therein. IF YOU HAVE NO + * AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS SOFTWARE IN ANY + * WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE ALL USE OF + * THE SOFTWARE. + * + * Except as expressly set forth in the Authorized License, + * 1. This program, including its structure, sequence and organization, + * constitutes the valuable trade secrets of Broadcom, and you shall use + * all reasonable efforts to protect the confidentiality thereof, and to + * use this information only in connection with your use of Broadcom + * integrated circuit products. + * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" + * AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR + * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH + * RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY DISCLAIMS ANY AND ALL + * IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS + * FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, + * QUIET ENJOYMENT, QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. YOU + * ASSUME THE ENTIRE RISK ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE. + * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS + * LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, + * OR EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO + * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS + * OF THE AMOUNT ACTUALLY PAID FOR THE SOFTWARE ITSELF OR U.S. $1, WHICHEVER + * IS GREATER. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF + * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY. + *****************************************************************************/ + +#include "interface/vcos/vcos.h" + +#if defined( __KERNEL__ ) +#include +#include +#else +#include +#endif + +#include + +/** 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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_tls.h b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_tls.h new file mode 100644 index 0000000..6460ae7 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_generic_tls.h @@ -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 (tlsslots[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 (tlsslots[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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_init.c b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_init.c new file mode 100644 index 0000000..6f4c1bb --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_init.c @@ -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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_joinable_thread_from_plain.h b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_joinable_thread_from_plain.h new file mode 100644 index 0000000..4471168 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_joinable_thread_from_plain.h @@ -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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_latch_from_sem.h b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_latch_from_sem.h new file mode 100644 index 0000000..94f4b13 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_latch_from_sem.h @@ -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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_logcat.c b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_logcat.c new file mode 100644 index 0000000..5dd5fbd --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_logcat.c @@ -0,0 +1,587 @@ +/* +Copyright (c) 2012, Broadcom Europe Ltd +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 + +/* For now, do not link logging categories into linked lists + * as it breaks when people unload shared libraries without + * getting the counts right. + */ +#ifdef __VIDEOCORE__ +#define REGISTER_CATEGORIES 1 +#else +#define REGISTER_CATEGORIES 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 ); + + if (!REGISTER_CATEGORIES) + return; + + 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 + * (,)* + * + * 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; + + if (!REGISTER_CATEGORIES) + return; + + 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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_mem_from_malloc.c b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_mem_from_malloc.c new file mode 100644 index 0000000..02f9f28 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_mem_from_malloc.c @@ -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 +#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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_mem_from_malloc.h b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_mem_from_malloc.h new file mode 100644 index 0000000..401a4fc --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_mem_from_malloc.h @@ -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. +*/ + +/*============================================================================= +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); +} + + +#endif /* VCOS_INLINE_BODIES */ + + diff --git a/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_msgqueue.c b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_msgqueue.c new file mode 100644 index 0000000..b8e558b --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_msgqueue.c @@ -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 +#include +#include + +#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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_mutexes_are_reentrant.h b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_mutexes_are_reentrant.h new file mode 100644 index 0000000..976b61a --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_mutexes_are_reentrant.h @@ -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/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_thread_reaper.h b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_thread_reaper.h new file mode 100644 index 0000000..4190dba --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/generic/vcos_thread_reaper.h @@ -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/external_src/raspicam-0.1.3/dependencies/vcos/glibc/vcos_backtrace.c b/external_src/raspicam-0.1.3/dependencies/vcos/glibc/vcos_backtrace.c new file mode 100644 index 0000000..3bb8aa3 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/glibc/vcos_backtrace.c @@ -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 +#ifdef HAVE_CMAKE_CONFIG +#include "cmake_config.h" +#endif +#ifdef HAVE_EXECINFO_H +#include +#endif +#include +#include +#include + +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 + +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/external_src/raspicam-0.1.3/dependencies/vcos/pthreads/vcos_futex_mutex.h b/external_src/raspicam-0.1.3/dependencies/vcos/pthreads/vcos_futex_mutex.h new file mode 100644 index 0000000..3c44720 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/pthreads/vcos_futex_mutex.h @@ -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/external_src/raspicam-0.1.3/dependencies/vcos/pthreads/vcos_platform.h b/external_src/raspicam-0.1.3/dependencies/vcos/pthreads/vcos_platform.h new file mode 100755 index 0000000..01d5c01 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/pthreads/vcos_platform.h @@ -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. +*/ + +/*============================================================================= +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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 "generic/vcos_generic_event_flags.h" +#include "generic/vcos_generic_blockpool.h" +#include "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(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(); +} + +/* + * 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: + 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); +} + +#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 + +#if defined(linux) || defined(_HAVE_SBRK) + +/* not exactly the free memory, but a measure of it */ + +VCOS_INLINE_IMPL +unsigned long vcos_get_free_mem(void) { + return (unsigned long)sbrk(0); +} + +#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 "generic/vcos_generic_reentrant_mtx.h" +#include "generic/vcos_generic_named_sem.h" +#include "generic/vcos_generic_quickslow_mutex.h" +#include "generic/vcos_common.h" + +#define _VCOS_LOG_LEVEL() getenv("VC_LOGLEVEL") + +VCOS_STATIC_INLINE +char *vcos_strdup(const char *str) +{ + return strdup(str); +} + +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/external_src/raspicam-0.1.3/dependencies/vcos/pthreads/vcos_platform_types.h b/external_src/raspicam-0.1.3/dependencies/vcos/pthreads/vcos_platform_types.h new file mode 100644 index 0000000..1a8734b --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/pthreads/vcos_platform_types.h @@ -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 "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/external_src/raspicam-0.1.3/dependencies/vcos/pthreads/vcos_pthreads.c b/external_src/raspicam-0.1.3/dependencies/vcos/pthreads/vcos_pthreads.c new file mode 100644 index 0000000..fdc8bc4 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/pthreads/vcos_pthreads.c @@ -0,0 +1,902 @@ +/* +Copyright (c) 2012, Broadcom Europe Ltd +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 +#include +#include +#include +#include +#include + +/* 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 +#endif + +#ifdef HAVE_CMAKE_CONFIG +#include "cmake_config.h" +#endif + +#ifdef HAVE_MTRACE +#include +#endif + +#if defined(ANDROID) +#include +#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(¤t_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; iat_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(¤t_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_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_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_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_timer_reset(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay_ms) +{ + vcos_timer_set(timer, delay_ms); +} + +void vcos_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/external_src/raspicam-0.1.3/dependencies/vcos/user_nodefs.h b/external_src/raspicam-0.1.3/dependencies/vcos/user_nodefs.h new file mode 100644 index 0000000..ded2fb4 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/user_nodefs.h @@ -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/external_src/raspicam-0.1.3/dependencies/vcos/vcos.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos.h new file mode 100644 index 0000000..e20b009 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos.h @@ -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. +*/ + +/*============================================================================= +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 "vcos_assert.h" +#include "vcos_types.h" +#include "pthreads/vcos_platform.h" + +#ifndef VCOS_INIT_H +#include "vcos_init.h" +#endif + +#ifndef VCOS_SEMAPHORE_H +#include "vcos_semaphore.h" +#endif + +#ifndef VCOS_THREAD_H +#include "vcos_thread.h" +#endif + +#ifndef VCOS_MUTEX_H +#include "vcos_mutex.h" +#endif + +#ifndef VCOS_MEM_H +#include "vcos_mem.h" +#endif + +#ifndef VCOS_LOGGING_H +#include "vcos_logging.h" +#endif + +#ifndef VCOS_STRING_H +#include "vcos_string.h" +#endif + +#ifndef VCOS_EVENT_H +#include "vcos_event.h" +#endif + +#ifndef VCOS_THREAD_ATTR_H +#include "vcos_thread_attr.h" +#endif + +#ifndef VCOS_TLS_H +#include "vcos_tls.h" +#endif + +#ifndef VCOS_REENTRANT_MUTEX_H +#include "vcos_reentrant_mutex.h" +#endif + +#ifndef VCOS_NAMED_SEMAPHORE_H +#include "vcos_named_semaphore.h" +#endif + +#ifndef VCOS_QUICKSLOW_MUTEX_H +#include "vcos_quickslow_mutex.h" +#endif + +/* Headers with predicates */ + +#if VCOS_HAVE_EVENT_FLAGS +#include "vcos_event_flags.h" +#endif + +#if VCOS_HAVE_QUEUE +#include "vcos_queue.h" +#endif + +#if VCOS_HAVE_LEGACY_ISR +#include "vcos_legacy_isr.h" +#endif + +#if VCOS_HAVE_TIMER +#include "vcos_timer.h" +#endif + +#if VCOS_HAVE_MEMPOOL +#include "vcos_mempool.h" +#endif + +#if VCOS_HAVE_ISR +#include "vcos_isr.h" +#endif + +#if VCOS_HAVE_ATOMIC_FLAGS +#include "vcos_atomic_flags.h" +#endif + +#if VCOS_HAVE_ONCE +#include "vcos_once.h" +#endif + +#if VCOS_HAVE_BLOCK_POOL +#include "vcos_blockpool.h" +#endif + +#if VCOS_HAVE_FILE +#include "vcos_file.h" +#endif + +#if VCOS_HAVE_CFG +#include "vcos_cfg.h" +#endif + +#if VCOS_HAVE_CMD +#include "vcos_cmd.h" +#endif + +#endif /* VCOS_H */ + diff --git a/external_src/raspicam-0.1.3/dependencies/vcos/vcos_assert.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_assert.h new file mode 100644 index 0000000..ff5b971 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_assert.h @@ -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 "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 "vcos_types.h" + +#ifdef __COVERITY__ +#include "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_MSG("%s", #cond), VCOS_ASSERT_BKPT) ) +#endif + +#ifndef vcos_assert_msg +#define vcos_assert_msg(cond, ...) \ + ( (cond) ? (void)0 : (VCOS_ASSERT_MSG(__VA_ARGS__), VCOS_ASSERT_BKPT) ) +#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_MSG("%s", #cond), VCOS_ASSERT_BKPT, vcos_abort()) ) +#endif + +#ifndef vcos_demand_msg +#define vcos_demand_msg(cond, ...) \ + ( (cond) ? (void)0 : (VCOS_ASSERT_MSG(__VA_ARGS__), VCOS_ASSERT_BKPT, 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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_atomic_flags.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_atomic_flags.h new file mode 100644 index 0000000..1f743fa --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_atomic_flags.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_attr.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_attr.h new file mode 100644 index 0000000..33f7eee --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_attr.h @@ -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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_blockpool.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_blockpool.h new file mode 100644 index 0000000..3ac1e25 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_blockpool.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_build_info.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_build_info.h new file mode 100644 index 0000000..710619e --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_build_info.h @@ -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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_cfg.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_cfg.h new file mode 100644 index 0000000..c510624 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_cfg.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_cmd.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_cmd.h new file mode 100644 index 0000000..16b1531 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_cmd.h @@ -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. +*/ + +#if !defined( VCOS_CMD_H ) +#define VCOS_CMD_H + +/* ---- Include Files ----------------------------------------------------- */ + +#ifndef VCOS_H +#include "vcos.h" +#endif +#include "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. + */ +VCOSPRE_ void VCOSPOST_ vcos_cmd_always_log_output( 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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_ctype.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_ctype.h new file mode 100644 index 0000000..64bda96 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_ctype.h @@ -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 +#else +#include +#endif + +#endif + diff --git a/external_src/raspicam-0.1.3/dependencies/vcos/vcos_dlfcn.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_dlfcn.h new file mode 100644 index 0000000..1d563d5 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_dlfcn.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_event.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_event.h new file mode 100644 index 0000000..ddf4b4a --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_event.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_event_flags.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_event_flags.h new file mode 100644 index 0000000..e539ec9 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_event_flags.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_init.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_init.h new file mode 100644 index 0000000..20e149f --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_init.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_inttypes.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_inttypes.h new file mode 100644 index 0000000..ba254d5 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_inttypes.h @@ -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 . The vcos versions initially only provide the + * most common printf() macros. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef __cplusplus +} +#endif + +#endif /* VCOS_INTTYPES_H */ diff --git a/external_src/raspicam-0.1.3/dependencies/vcos/vcos_isr.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_isr.h new file mode 100644 index 0000000..bf2e150 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_isr.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_legacy_isr.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_legacy_isr.h new file mode 100644 index 0000000..62d1498 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_legacy_isr.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_logging.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_logging.h new file mode 100644 index 0000000..2a48d75 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_logging.h @@ -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 + +#include "vcos_types.h" +#include "pthreads/vcos_platform.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 + * + * 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 "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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_logging_control.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_logging_control.h new file mode 100644 index 0000000..b180ad8 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_logging_control.h @@ -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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_lowlevel_thread.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_lowlevel_thread.h new file mode 100644 index 0000000..2bcfebf --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_lowlevel_thread.h @@ -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 "vcos_types.h" +#ifndef VCOS_PLATFORM_H +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_mem.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_mem.h new file mode 100644 index 0000000..687fb99 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_mem.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_mempool.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_mempool.h new file mode 100644 index 0000000..8f5b84d --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_mempool.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_msgqueue.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_msgqueue.h new file mode 100644 index 0000000..6da69d7 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_msgqueue.h @@ -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 "pthreads/vcos_platform.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; + +/** Initalise 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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_mutex.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_mutex.h new file mode 100644 index 0000000..4a03853 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_mutex.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.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 succesfully 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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_named_semaphore.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_named_semaphore.h new file mode 100644 index 0000000..00022eb --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_named_semaphore.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_once.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_once.h new file mode 100644 index 0000000..4cca139 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_once.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_queue.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_queue.h new file mode 100644 index 0000000..1f28e1d --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_queue.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_quickslow_mutex.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_quickslow_mutex.h new file mode 100644 index 0000000..229d518 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_quickslow_mutex.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_reentrant_mutex.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_reentrant_mutex.h new file mode 100644 index 0000000..1a1ca56 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_reentrant_mutex.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_semaphore.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_semaphore.h new file mode 100644 index 0000000..c9c3199 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_semaphore.h @@ -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 "vcos_types.h" +#ifndef VCOS_PLATFORM_H +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_stdbool.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_stdbool.h new file mode 100644 index 0000000..25b0e09 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_stdbool.h @@ -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 +#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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_stdint.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_stdint.h new file mode 100644 index 0000000..1ea1aa3 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_stdint.h @@ -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 . + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined (VCMODS_LCC) + +#include + +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 + +#endif + +#ifdef __cplusplus +} +#endif +#endif /* VCOS_STDINT_H */ diff --git a/external_src/raspicam-0.1.3/dependencies/vcos/vcos_string.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_string.h new file mode 100644 index 0000000..133c0c7 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_string.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.h" + +#ifdef __KERNEL__ +#include +#else +#include +#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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_thread.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_thread.h new file mode 100644 index 0000000..0a49083 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_thread.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_thread_attr.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_thread_attr.h new file mode 100644 index 0000000..9eddd69 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_thread_attr.h @@ -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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_timer.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_timer.h new file mode 100644 index 0000000..0e198e1 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_timer.h @@ -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 "vcos_types.h" +#ifndef VCOS_PLATFORM_H +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_tls.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_tls.h new file mode 100644 index 0000000..ca6259e --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_tls.h @@ -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 "vcos_types.h" +#include "pthreads/vcos_platform.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/external_src/raspicam-0.1.3/dependencies/vcos/vcos_types.h b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_types.h new file mode 100644 index 0000000..4e0ad19 --- /dev/null +++ b/external_src/raspicam-0.1.3/dependencies/vcos/vcos_types.h @@ -0,0 +1,283 @@ +/* +Copyright (c) 2012, Broadcom Europe Ltd +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 +#include "pthreads/vcos_platform_types.h" +#include "vcos_attr.h" + +#if !defined(VCOSPRE_) || !defined(VCOSPOST_) +#error VCOSPRE_ and 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_.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 "" +# 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 + +#endif diff --git a/external_src/raspicam-0.1.3/src/CMakeLists.txt b/external_src/raspicam-0.1.3/src/CMakeLists.txt new file mode 100644 index 0000000..09640b2 --- /dev/null +++ b/external_src/raspicam-0.1.3/src/CMakeLists.txt @@ -0,0 +1,53 @@ +INCLUDE_DIRECTORIES(.) +SET(private_hdrs_base "private/private_types.h private/private_impl.h exceptions.h private/threadcondition.h ") +SET(private_still_hdrs_base "private_still/private_still_types.h private/private_still_impl.h") + +SET(public_hdrs_base raspicamtypes.h raspicam.h) + +SET(srcs_base raspicam.cpp raspicam_still.cpp private/private_impl.cpp private/threadcondition.cpp private_still/private_still_impl.cpp) +if(NOT( ${CMAKE_SYSTEM_PROCESSOR} MATCHES arm*) )#in a pc, adds fake dependencies to mmal functions to enable compilation +SET(srcs_base ${srcs_base} private/fake_mmal_dependencies.cpp) +endif() +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ) + +ADD_LIBRARY(${PROJECT_NAME} ${hdrs_base} ${srcs_base} ) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES # create *nix style library versions + symbolic links + DEFINE_SYMBOL DSO_EXPORTS + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_SOVERSION} + CLEAN_DIRECT_OUTPUT 1 # allow creating static and shared libs without conflicts + OUTPUT_NAME "${PROJECT_NAME}${PROJECT_DLLVERSION}" # avoid conflicts between library and binary target names +) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${REQUIRED_LIBRARIES} ) + +INSTALL(TARGETS ${PROJECT_NAME} + RUNTIME DESTINATION bin COMPONENT main + LIBRARY DESTINATION lib PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE COMPONENT main + ARCHIVE DESTINATION lib COMPONENT main) +#Add opencv component if required +#Opencv Lib +IF (${OpenCV_FOUND}) +message(STATUS "Adding cv library") +SET(hdrs_cv raspicam_cv.h raspicam_still_cv.h) +SET(srcs_cv raspicam_cv.cpp raspicam_still_cv.cpp) +ADD_LIBRARY(${PROJECT_NAME}_cv ${hdrs_cv} ${srcs_cv} ) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES # create *nix style library versions + symbolic links + DEFINE_SYMBOL DSO_EXPORTS + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_SOVERSION} + CLEAN_DIRECT_OUTPUT 1 # allow creating static and shared libs without conflicts + OUTPUT_NAME "${PROJECT_NAME}${PROJECT_DLLVERSION}" # avoid conflicts between library and binary target names +) +TARGET_LINK_LIBRARIES(${PROJECT_NAME}_cv ${REQUIRED_LIBRARIES} ${OpenCV_LIBS} ) +INSTALL(TARGETS ${PROJECT_NAME}_cv + RUNTIME DESTINATION bin COMPONENT main + LIBRARY DESTINATION lib PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE COMPONENT main + ARCHIVE DESTINATION lib COMPONENT main) +ENDIF() + + +#Installation of all header files +INSTALL(FILES ${public_hdrs_base} ${hdrs_cv} + DESTINATION include/${PROJECT_NAME} + COMPONENT main) + diff --git a/external_src/raspicam-0.1.3/src/private/exceptions.h b/external_src/raspicam-0.1.3/src/private/exceptions.h new file mode 100644 index 0000000..91a34a3 --- /dev/null +++ b/external_src/raspicam-0.1.3/src/private/exceptions.h @@ -0,0 +1,114 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 _RaspiCam__Exceptions_h +#define _RaspiCam__Exceptions_h +#include +#include +#include +namespace raspicam { + +/** + * Types of valid exceptions + */ +class Exceptions { +public: + static const int Generic=81799; +}; + + + + +/*! + The standard exception class. + */ +class Exception : public std::exception +{ +public: + /*! + Default constructor + */ + Exception() { + code = 0; + line = 0; + } + /*! + Full constructor. Normally the constuctor is not called explicitly. + Instead, the macros CV_Error(), CV_Error_() and CV_Assert() are used. + */ + Exception(int _code, const std::string& _err, const std::string& _func, const std::string& _file, int _line) + : code(_code), err(_err), func(_func), file(_file), line(_line) + { + formatMessage(); + } + virtual ~Exception() throw() {} + + /*! + \return the error description and the context as a text string. + */ + virtual const char *what() const throw() { + return msg.c_str(); + } + void formatMessage() + { + if ( func.size() > 0 ) + msg = format("%s:%d: error: (%d) %s in function %s\n", file.c_str(), line, code, err.c_str(), func.c_str()); + else + msg = format("%s:%d: error: (%d) %s\n", file.c_str(), line, code, err.c_str()); + } + + std::string msg; ///< the formatted error message + + int code; ///< error code @see CVStatus + std::string err; ///< error description + std::string func; ///< function name. Available only when the compiler supports __func__ macro + std::string file; ///< source file name where the error has occured + int line; ///< line number in the source file where the error has occured + +private: + std::string format( const char* fmt, ... ) + { + char buf[1 << 16]; + va_list args; + va_start( args, fmt ); + vsprintf( buf, fmt, args ); + return std::string(buf); + } +}; + +}; +#endif diff --git a/external_src/raspicam-0.1.3/src/private/fake_mmal_dependencies.cpp b/external_src/raspicam-0.1.3/src/private/fake_mmal_dependencies.cpp new file mode 100644 index 0000000..001bd8a --- /dev/null +++ b/external_src/raspicam-0.1.3/src/private/fake_mmal_dependencies.cpp @@ -0,0 +1,395 @@ +#include "mmal/util/mmal_default_components.h" +#include "mmal/util/mmal_util.h" +#include "mmal/util/mmal_util_params.h" +#include "mmal/mmal.h" +#include "mmal/util/mmal_connection.h" + MMAL_BUFFER_HEADER_T *mmal_queue_get(MMAL_QUEUE_T *queue){} +MMAL_STATUS_T mmal_buffer_header_mem_lock(MMAL_BUFFER_HEADER_T *header){} + +void mmal_buffer_header_mem_unlock(MMAL_BUFFER_HEADER_T *header){} + void mmal_port_pool_destroy(MMAL_PORT_T *port, MMAL_POOL_T *pool){} + +/** 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){} + + + + +/** 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){} + + +/** 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: + *
    + *
  • The port shall be populated with a pool of buffers, allocated as required, according + * to the buffer_num and buffer_size values. + *
  • 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. + *
+ * + * @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){} +/** 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){} + + + +/** 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){} + + +/** 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 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 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 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){} + + + +/** 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){} + +/** 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){} +/** 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){} diff --git a/external_src/raspicam-0.1.3/src/private/private_impl.cpp b/external_src/raspicam-0.1.3/src/private/private_impl.cpp new file mode 100644 index 0000000..2f549e5 --- /dev/null +++ b/external_src/raspicam-0.1.3/src/private/private_impl.cpp @@ -0,0 +1,812 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 "private_impl.h" +#include +#include +#include "mmal/util/mmal_util.h" +#include "mmal/util/mmal_util_params.h" +#include "mmal/util/mmal_default_components.h" +using namespace std; +namespace raspicam { + namespace _private{ +#define MMAL_CAMERA_VIDEO_PORT 1 +#define MMAL_CAMERA_CAPTURE_PORT 2 +#define VIDEO_FRAME_RATE_DEN 1 +#define VIDEO_OUTPUT_BUFFERS_NUM 3 + + + Private_Impl::Private_Impl() { + camera_video_port = NULL; +// camera_still_port = NULL; + _isOpened=false; + _isCapturing=false; + //set default state params + setDefaultStateParams(); + } + + Private_Impl::~Private_Impl() { + + release(); + } + + void Private_Impl::setDefaultStateParams() { + + // Default everything to zero + memset ( &State, 0, sizeof ( RASPIVID_STATE ) ); + State.framerate = 30; + State.width = 1280; // use a multiple of 320 (640, 1280) + State.height = 960; // use a multiple of 240 (480, 960) + State.sharpness = 0; + State.contrast = 0; + State.brightness = 50; + State.saturation = 0; + State.ISO = 400; + State.videoStabilisation = false; + State.exposureCompensation = 0; + State.captureFtm=RASPICAM_FORMAT_RGB; + State.rpc_exposureMode = RASPICAM_EXPOSURE_AUTO; + State.rpc_exposureMeterMode = RASPICAM_METERING_AVERAGE; + State.rpc_awbMode = RASPICAM_AWB_AUTO; + State.rpc_imageEffect = RASPICAM_IMAGE_EFFECT_NONE; + State.colourEffects.enable = 0; + State.colourEffects.u = 128; + State.colourEffects.v = 128; + State.rotation = 0; + State.hflip = State.vflip = 0; + State.roi.x = State.roi.y = 0.0; + State.roi.w = State.roi.h = 1.0; + State.shutterSpeed=0;//auto + State.awbg_red=1.0; + State.awbg_blue=1.0; + + } + bool Private_Impl::open ( bool StartCapture ) { + if ( _isOpened ) return false; //already opened +// create camera + if ( ! create_camera_component ( &State ) ) { + cerr<<__func__<<" Failed to create camera component"<<__FILE__<<" "<<__LINE__<output[MMAL_CAMERA_VIDEO_PORT]; + callback_data.pstate = &State; + // assign data to use for callback + camera_video_port->userdata = ( struct MMAL_PORT_USERDATA_T * ) &callback_data; + + _isOpened=true; + if ( StartCapture ) return startCapture(); + else return true; + } + /** + */ + bool Private_Impl::startCapture() { + if ( !_isOpened ) { + cerr<<__FILE__<<":"<<__LINE__<<":"<<__func__<<" not opened."<queue ); + int q; + for ( q=0; qqueue ); + + if ( !buffer ) + cerr<<"Unable to get a required buffer"<is_enabled ) { + mmal_port_disable ( camera_video_port ); + camera_video_port = NULL; + } + //// + // Disable all our ports that are not handled by connections + if ( State.camera_component ) + mmal_component_disable ( State.camera_component ); + + + destroy_camera_component ( &State ); + + _isOpened=false; + _isCapturing=false; + + } + /** + * + */ + bool Private_Impl::grab() { + if ( !isCapturing() ) return false; + callback_data.waitForFrame(); + return true; + } + /** + * + */ + void Private_Impl::retrieve ( unsigned char *data,RASPICAM_FORMAT type ) { + if ( callback_data._buffData.size==0 ) return; + if ( type!=RASPICAM_FORMAT_IGNORE ) { + cerr<<__FILE__<<":"<<__LINE__<<" :Private_Impl::retrieve type is not RASPICAM_FORMAT_IGNORE as it should be"<video_pool ) + mmal_port_pool_destroy ( state->camera_component->output[MMAL_CAMERA_VIDEO_PORT], state->video_pool ); + if ( state->camera_component ) { + mmal_component_destroy ( state->camera_component ); + state->camera_component = NULL; + } + } + MMAL_COMPONENT_T *Private_Impl::create_camera_component ( RASPIVID_STATE *state ) { + MMAL_COMPONENT_T *camera = 0; + MMAL_ES_FORMAT_T *format; + MMAL_PORT_T *video_port = NULL; + + MMAL_STATUS_T status; + /* Create the component */ + status = mmal_component_create ( MMAL_COMPONENT_DEFAULT_CAMERA, &camera ); + + if ( status != MMAL_SUCCESS ) { + cerr<< ( "Failed to create camera component" ); + return 0; + } + + if ( !camera->output_num ) { + cerr<< ( "Camera doesn't have output ports" ); + mmal_component_destroy ( camera ); + return 0; + } + + video_port = camera->output[MMAL_CAMERA_VIDEO_PORT]; + + // set up the camera configuration + + MMAL_PARAMETER_CAMERA_CONFIG_T cam_config; + cam_config.hdr.id=MMAL_PARAMETER_CAMERA_CONFIG; + cam_config.hdr.size=sizeof ( cam_config ); + cam_config.max_stills_w = state->width; + cam_config.max_stills_h = state->height; + cam_config.stills_yuv422 = 0; + cam_config.one_shot_stills = 0; + cam_config.max_preview_video_w = state->width; + cam_config.max_preview_video_h = state->height; + cam_config.num_preview_video_frames = 3; + cam_config.stills_capture_circular_buffer_height = 0; + cam_config.fast_preview_resume = 0; + cam_config.use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RESET_STC; + mmal_port_parameter_set ( camera->control, &cam_config.hdr ); + + // Set the encode format on the video port + + format = video_port->format; + format->encoding_variant = convertFormat ( State.captureFtm ); + format->encoding = convertFormat ( State.captureFtm ); + 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 ) { + cerr<< ( "camera video format couldn't be set" ); + mmal_component_destroy ( camera ); + return 0; + } + + // PR : plug the callback to the video port + status = mmal_port_enable ( video_port,video_buffer_callback ); + if ( status ) { + cerr<< ( "camera video callback2 error" ); + mmal_component_destroy ( camera ); + return 0; + } + + // 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; + + + + //PR : create pool of message on video port + MMAL_POOL_T *pool; + video_port->buffer_size = video_port->buffer_size_recommended; + video_port->buffer_num = video_port->buffer_num_recommended; + pool = mmal_port_pool_create ( video_port, video_port->buffer_num, video_port->buffer_size ); + if ( !pool ) { + cerr<< ( "Failed to create buffer header pool for video output port" ); + } + state->video_pool = pool; + + + /* Enable component */ + status = mmal_component_enable ( camera ); + + if ( status ) { + cerr<< ( "camera component couldn't be enabled" ); + mmal_component_destroy ( camera ); + return 0; + } + + state->camera_component = camera;//this needs to be before set_all_parameters + + return camera; + } + + + void Private_Impl::commitBrightness() { + mmal_port_parameter_set_rational ( State.camera_component->control, MMAL_PARAMETER_BRIGHTNESS, ( MMAL_RATIONAL_T ) { + State.brightness, 100 + } ); + } + + + void Private_Impl::commitRotation() { + int rotation = int ( State.rotation / 90 ) * 90; + mmal_port_parameter_set_int32 ( State.camera_component->output[0], MMAL_PARAMETER_ROTATION,rotation ); + mmal_port_parameter_set_int32 ( State.camera_component->output[1], MMAL_PARAMETER_ROTATION,rotation ); + mmal_port_parameter_set_int32 ( State.camera_component->output[2], MMAL_PARAMETER_ROTATION, rotation ); + } + + void Private_Impl::commitISO() { + if ( mmal_port_parameter_set_uint32 ( State.camera_component->control, MMAL_PARAMETER_ISO, State.ISO ) != MMAL_SUCCESS ) + cout << __func__ << ": Failed to set ISO parameter.\n"; + } + + void Private_Impl::commitSharpness() { + if ( mmal_port_parameter_set_rational ( State.camera_component->control, MMAL_PARAMETER_SHARPNESS, ( MMAL_RATIONAL_T ) { + State.sharpness, 100 + } ) != MMAL_SUCCESS ) + cout << __func__ << ": Failed to set sharpness parameter.\n"; + } + + void Private_Impl::commitShutterSpeed() { + if ( mmal_port_parameter_set_uint32 ( State.camera_component->control, MMAL_PARAMETER_SHUTTER_SPEED, State.shutterSpeed ) != MMAL_SUCCESS ) + cout << __func__ << ": Failed to set shutter parameter.\n"; + } + + + + void Private_Impl::commitContrast() { + if ( mmal_port_parameter_set_rational ( State.camera_component->control, MMAL_PARAMETER_CONTRAST, ( MMAL_RATIONAL_T ) { + State.contrast, 100 + } ) != MMAL_SUCCESS ) + cout << __func__ << ": Failed to set contrast parameter.\n"; + } + + void Private_Impl::commitSaturation() { + if ( mmal_port_parameter_set_rational ( State.camera_component->control, MMAL_PARAMETER_SATURATION, ( MMAL_RATIONAL_T ) { + State.saturation, 100 + } ) != MMAL_SUCCESS ) + cout << __func__ << ": Failed to set saturation parameter.\n"; + } + + void Private_Impl::commitExposure() { + MMAL_PARAMETER_EXPOSUREMODE_T exp_mode = {{MMAL_PARAMETER_EXPOSURE_MODE,sizeof ( exp_mode ) }, convertExposure ( State.rpc_exposureMode ) }; + if ( mmal_port_parameter_set ( State.camera_component->control, &exp_mode.hdr ) != MMAL_SUCCESS ) + cout << __func__ << ": Failed to set exposure parameter.\n"; + } + /** + * 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 + */ + void Private_Impl::commitExposureCompensation() { + if ( mmal_port_parameter_set_int32 ( State.camera_component->control, MMAL_PARAMETER_EXPOSURE_COMP , State.exposureCompensation ) !=MMAL_SUCCESS ) + cout << __func__ << ": Failed to set Exposure Compensation parameter.\n"; + + } + + + void Private_Impl::commitAWB() { + MMAL_PARAMETER_AWBMODE_T param = {{MMAL_PARAMETER_AWB_MODE,sizeof ( param ) }, convertAWB ( State.rpc_awbMode ) }; + if ( mmal_port_parameter_set ( State.camera_component->control, ¶m.hdr ) != MMAL_SUCCESS ) + cout << __func__ << ": Failed to set AWB parameter.\n"; + } + + void Private_Impl::commitImageEffect() { + MMAL_PARAMETER_IMAGEFX_T imgFX = {{MMAL_PARAMETER_IMAGE_EFFECT,sizeof ( imgFX ) }, convertImageEffect ( State.rpc_imageEffect ) }; + if ( mmal_port_parameter_set ( State.camera_component->control, &imgFX.hdr ) != MMAL_SUCCESS ) + cout << __func__ << ": Failed to set image effect parameter.\n"; + } + + void Private_Impl::commitMetering() { + MMAL_PARAMETER_EXPOSUREMETERINGMODE_T meter_mode = {{MMAL_PARAMETER_EXP_METERING_MODE, sizeof ( meter_mode ) }, convertMetering ( State.rpc_exposureMeterMode ) }; + if ( mmal_port_parameter_set ( State.camera_component->control, &meter_mode.hdr ) != MMAL_SUCCESS ) + cout << __func__ << ": Failed to set metering parameter.\n"; + } + + void Private_Impl::commitFlips() { + MMAL_PARAMETER_MIRROR_T mirror = {{MMAL_PARAMETER_MIRROR, sizeof ( MMAL_PARAMETER_MIRROR_T ) }, MMAL_PARAM_MIRROR_NONE}; + if ( State.hflip && State.vflip ) + mirror.value = MMAL_PARAM_MIRROR_BOTH; + else if ( State.hflip ) + mirror.value = MMAL_PARAM_MIRROR_HORIZONTAL; + else if ( State.vflip ) + mirror.value = MMAL_PARAM_MIRROR_VERTICAL; + if ( mmal_port_parameter_set ( State.camera_component->output[0], &mirror.hdr ) != MMAL_SUCCESS || + mmal_port_parameter_set ( State.camera_component->output[1], &mirror.hdr ) != MMAL_SUCCESS || + mmal_port_parameter_set ( State.camera_component->output[2], &mirror.hdr ) ) + cout << __func__ << ": Failed to set horizontal/vertical flip parameter.\n"; + } + + + /** + * 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. + */ + void Private_Impl::commitParameters ( ) { + assert ( State.camera_component!=0 ); + commitSaturation(); + commitSharpness(); + commitContrast(); + commitBrightness(); + commitISO(); + if ( State.shutterSpeed!=0 ) { + commitShutterSpeed(); + State.rpc_exposureMode=RASPICAM_EXPOSURE_FIXEDFPS; + commitExposure(); + } else commitExposure(); + commitExposureCompensation(); + commitMetering(); + commitImageEffect(); + commitRotation(); + commitFlips(); + commitVideoStabilization(); + commitAWB(); + commitAWB_RB(); + + } + void Private_Impl::commitVideoStabilization() { + // Set Video Stabilization + if ( mmal_port_parameter_set_boolean ( State.camera_component->control, MMAL_PARAMETER_VIDEO_STABILISATION, State.videoStabilisation ) != MMAL_SUCCESS ) + cout << __func__ << ": Failed to set video stabilization parameter.\n"; + } + + + + void Private_Impl::video_buffer_callback ( MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer ) { + MMAL_BUFFER_HEADER_T *new_buffer; + PORT_USERDATA *pData = ( PORT_USERDATA * ) port->userdata; + + bool hasGrabbed=false; +// pData->_mutex.lock(); + std::unique_lock lck ( pData->_mutex ); + if ( pData ) { + if ( pData->wantToGrab && buffer->length ) { + mmal_buffer_header_mem_lock ( buffer ); + pData->_buffData.resize ( buffer->length ); + memcpy ( pData->_buffData.data,buffer->data,buffer->length ); + pData->wantToGrab =false; + hasGrabbed=true; + mmal_buffer_header_mem_unlock ( buffer ); + } + } + //pData->_mutex.unlock(); + // if ( hasGrabbed ) pData->Thcond.BroadCast(); //wake up waiting client + // 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->video_pool->queue ); + + if ( new_buffer ) + status = mmal_port_send_buffer ( port, new_buffer ); + + if ( !new_buffer || status != MMAL_SUCCESS ) + printf ( "Unable to return a buffer to the encoder port" ); + } + + if ( pData->pstate->shutterSpeed!=0 ) + mmal_port_parameter_set_uint32 ( pData->pstate->camera_component->control, MMAL_PARAMETER_SHUTTER_SPEED, pData->pstate->shutterSpeed ) ; + if ( hasGrabbed ) pData->Thcond.BroadCast(); //wake up waiting client + + } + + + + void Private_Impl::setWidth ( unsigned int width ) { + State.width = width; + } + + void Private_Impl::setHeight ( unsigned int height ) { + State.height = height; + } + void Private_Impl::setFormat ( RASPICAM_FORMAT fmt ) { + if ( isOpened() ) { + cerr<<__FILE__<<":"<<__LINE__<<":"<<__func__<<": can not change format with camera already opened"< 100 ) brightness = 100 ; + State.brightness = brightness; + if ( isOpened() ) commitBrightness(); + } + void Private_Impl::setShutterSpeed ( unsigned int shutter ) { + if ( shutter > 330000 ) + shutter = 330000; + State.shutterSpeed= shutter; + if ( isOpened() ) commitShutterSpeed(); + } + + + + + void Private_Impl::setRotation ( int rotation ) { + while ( rotation < 0 ) + rotation += 360; + if ( rotation >= 360 ) + rotation = rotation % 360; + State.rotation = rotation; + if ( isOpened() ) commitRotation(); + } + + void Private_Impl::setISO ( int iso ) { + State.ISO = iso; + if ( isOpened() ) commitISO(); + } + + void Private_Impl::setSharpness ( int sharpness ) { + if ( sharpness < -100 ) sharpness = -100; + if ( sharpness > 100 ) sharpness = 100; + State.sharpness = sharpness; + if ( isOpened() ) commitSharpness(); + } + + void Private_Impl::setContrast ( int contrast ) { + if ( contrast < -100 ) contrast = -100; + if ( contrast > 100 ) contrast = 100; + State.contrast = contrast; + if ( isOpened() ) commitContrast(); + } + + void Private_Impl::setSaturation ( int saturation ) { + if ( saturation < -100 ) saturation = -100; + if ( saturation > 100 ) saturation = 100; + State.saturation = saturation; + if ( isOpened() ) commitSaturation(); + } + + + void Private_Impl::setAWB_RB ( float red_g, float blue_g ) { + State.awbg_blue = blue_g; + State.awbg_red = red_g; + if ( isOpened() ) commitAWB_RB(); + } + void Private_Impl::setExposure ( RASPICAM_EXPOSURE exposure ) { + State.rpc_exposureMode = exposure; + if ( isOpened() ) commitExposure(); + } + + void Private_Impl::setAWB ( RASPICAM_AWB awb ) { + State.rpc_awbMode = awb; + if ( isOpened() ) commitAWB(); + } + + void Private_Impl::setImageEffect ( RASPICAM_IMAGE_EFFECT imageEffect ) { + State.rpc_imageEffect = imageEffect; + if ( isOpened() ) commitImageEffect(); + } + + void Private_Impl::setMetering ( RASPICAM_METERING metering ) { + State.rpc_exposureMeterMode = metering; + if ( isOpened() ) commitMetering(); + } + void Private_Impl::setExposureCompensation ( int val ) { + if ( val < -10 ) val= -10; + if ( val > 10 ) val = 10; + State.exposureCompensation=val; + if ( isOpened() ) commitExposureCompensation(); + } + + void Private_Impl::setHorizontalFlip ( bool hFlip ) { + State.hflip = hFlip; + if ( isOpened() ) commitFlips(); + } + + void Private_Impl::setVerticalFlip ( bool vFlip ) { + State.vflip = vFlip; + if ( isOpened() ) commitFlips(); + } + + + MMAL_PARAM_EXPOSUREMETERINGMODE_T Private_Impl::convertMetering ( RASPICAM_METERING metering ) { + switch ( metering ) { + case RASPICAM_METERING_AVERAGE: + return MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE; + case RASPICAM_METERING_SPOT: + return MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT; + case RASPICAM_METERING_BACKLIT: + return MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT; + case RASPICAM_METERING_MATRIX: + return MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX; + default: + return MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE; + } + } + MMAL_PARAM_EXPOSUREMODE_T Private_Impl::convertExposure ( RASPICAM_EXPOSURE exposure ) { + + switch ( exposure ) { + case RASPICAM_EXPOSURE_OFF: + return MMAL_PARAM_EXPOSUREMODE_OFF; + case RASPICAM_EXPOSURE_AUTO: + return MMAL_PARAM_EXPOSUREMODE_AUTO; + case RASPICAM_EXPOSURE_NIGHT: + return MMAL_PARAM_EXPOSUREMODE_NIGHT; + case RASPICAM_EXPOSURE_NIGHTPREVIEW: + return MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW; + case RASPICAM_EXPOSURE_BACKLIGHT: + return MMAL_PARAM_EXPOSUREMODE_BACKLIGHT; + case RASPICAM_EXPOSURE_SPOTLIGHT: + return MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT; + case RASPICAM_EXPOSURE_SPORTS: + return MMAL_PARAM_EXPOSUREMODE_SPORTS; + case RASPICAM_EXPOSURE_SNOW: + return MMAL_PARAM_EXPOSUREMODE_SNOW; + case RASPICAM_EXPOSURE_BEACH: + return MMAL_PARAM_EXPOSUREMODE_BEACH; + case RASPICAM_EXPOSURE_VERYLONG: + return MMAL_PARAM_EXPOSUREMODE_VERYLONG; + case RASPICAM_EXPOSURE_FIXEDFPS: + return MMAL_PARAM_EXPOSUREMODE_FIXEDFPS; + case RASPICAM_EXPOSURE_ANTISHAKE: + return MMAL_PARAM_EXPOSUREMODE_ANTISHAKE; + case RASPICAM_EXPOSURE_FIREWORKS: + return MMAL_PARAM_EXPOSUREMODE_FIREWORKS; + default: + return MMAL_PARAM_EXPOSUREMODE_AUTO; + } + } + + MMAL_PARAM_AWBMODE_T Private_Impl::convertAWB ( RASPICAM_AWB awb ) { + switch ( awb ) { + case RASPICAM_AWB_OFF: + return MMAL_PARAM_AWBMODE_OFF; + case RASPICAM_AWB_AUTO: + return MMAL_PARAM_AWBMODE_AUTO; + case RASPICAM_AWB_SUNLIGHT: + return MMAL_PARAM_AWBMODE_SUNLIGHT; + case RASPICAM_AWB_CLOUDY: + return MMAL_PARAM_AWBMODE_CLOUDY; + case RASPICAM_AWB_SHADE: + return MMAL_PARAM_AWBMODE_SHADE; + case RASPICAM_AWB_TUNGSTEN: + return MMAL_PARAM_AWBMODE_TUNGSTEN; + case RASPICAM_AWB_FLUORESCENT: + return MMAL_PARAM_AWBMODE_FLUORESCENT; + case RASPICAM_AWB_INCANDESCENT: + return MMAL_PARAM_AWBMODE_INCANDESCENT; + case RASPICAM_AWB_FLASH: + return MMAL_PARAM_AWBMODE_FLASH; + case RASPICAM_AWB_HORIZON: + return MMAL_PARAM_AWBMODE_HORIZON; + default: + return MMAL_PARAM_AWBMODE_AUTO; + } + } + + MMAL_PARAM_IMAGEFX_T Private_Impl::convertImageEffect ( RASPICAM_IMAGE_EFFECT imageEffect ) { + switch ( imageEffect ) { + case RASPICAM_IMAGE_EFFECT_NONE: + return MMAL_PARAM_IMAGEFX_NONE; + case RASPICAM_IMAGE_EFFECT_NEGATIVE: + return MMAL_PARAM_IMAGEFX_NEGATIVE; + case RASPICAM_IMAGE_EFFECT_SOLARIZE: + return MMAL_PARAM_IMAGEFX_SOLARIZE; + case RASPICAM_IMAGE_EFFECT_SKETCH: + return MMAL_PARAM_IMAGEFX_SKETCH; + case RASPICAM_IMAGE_EFFECT_DENOISE: + return MMAL_PARAM_IMAGEFX_DENOISE; + case RASPICAM_IMAGE_EFFECT_EMBOSS: + return MMAL_PARAM_IMAGEFX_EMBOSS; + case RASPICAM_IMAGE_EFFECT_OILPAINT: + return MMAL_PARAM_IMAGEFX_OILPAINT; + case RASPICAM_IMAGE_EFFECT_HATCH: + return MMAL_PARAM_IMAGEFX_HATCH; + case RASPICAM_IMAGE_EFFECT_GPEN: + return MMAL_PARAM_IMAGEFX_GPEN; + case RASPICAM_IMAGE_EFFECT_PASTEL: + return MMAL_PARAM_IMAGEFX_PASTEL; + case RASPICAM_IMAGE_EFFECT_WATERCOLOR: + return MMAL_PARAM_IMAGEFX_WATERCOLOUR; + case RASPICAM_IMAGE_EFFECT_FILM: + return MMAL_PARAM_IMAGEFX_FILM; + case RASPICAM_IMAGE_EFFECT_BLUR: + return MMAL_PARAM_IMAGEFX_BLUR; + case RASPICAM_IMAGE_EFFECT_SATURATION: + return MMAL_PARAM_IMAGEFX_SATURATION; + case RASPICAM_IMAGE_EFFECT_COLORSWAP: + return MMAL_PARAM_IMAGEFX_COLOURSWAP; + case RASPICAM_IMAGE_EFFECT_WASHEDOUT: + return MMAL_PARAM_IMAGEFX_WASHEDOUT; + case RASPICAM_IMAGE_EFFECT_POSTERISE: + return MMAL_PARAM_IMAGEFX_POSTERISE; + case RASPICAM_IMAGE_EFFECT_COLORPOINT: + return MMAL_PARAM_IMAGEFX_COLOURPOINT; + case RASPICAM_IMAGE_EFFECT_COLORBALANCE: + return MMAL_PARAM_IMAGEFX_COLOURBALANCE; + case RASPICAM_IMAGE_EFFECT_CARTOON: + return MMAL_PARAM_IMAGEFX_CARTOON; + default: + return MMAL_PARAM_IMAGEFX_NONE; + } + } + + int Private_Impl::convertFormat ( RASPICAM_FORMAT fmt ) { + switch ( fmt ) { + case RASPICAM_FORMAT_RGB: + return MMAL_ENCODING_BGR24; + case RASPICAM_FORMAT_BGR: + return MMAL_ENCODING_RGB24; + case RASPICAM_FORMAT_GRAY: + return MMAL_ENCODING_I420; + case RASPICAM_FORMAT_YUV420: + return MMAL_ENCODING_I420; + default: + return MMAL_ENCODING_I420; + } + } + + + //Returns an id of the camera. We assume the camera id is the one of the raspberry + //the id is obtained using raspberry serial number obtained in /proc/cpuinfo + string Private_Impl::getId() const{ + char serial[1024]; + serial[0]='\0'; + ifstream file ( "/proc/cpuinfo" ); + if ( !file ) { + cerr<<__FILE__<<" "<<__LINE__<<":"<<__func__<<"Could not read /proc/cpuinfo"<control, ¶m.hdr) != MMAL_SUCCESS ) + cout << __func__ << ": Failed to set AWBG gains parameter.\n"; + } + }; +}; + diff --git a/external_src/raspicam-0.1.3/src/private/private_impl.h b/external_src/raspicam-0.1.3/src/private/private_impl.h new file mode 100644 index 0000000..8414e85 --- /dev/null +++ b/external_src/raspicam-0.1.3/src/private/private_impl.h @@ -0,0 +1,280 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 _Private_RaspiCam_IMPL_H +#define _Private_RaspiCam_IMPL_H +#include "mmal/mmal.h" +//#include "mmal_connection.h" +#include +#include +#include "raspicamtypes.h" +#include "private_types.h" +#include "threadcondition.h" +namespace raspicam { + namespace _private + { + + /**Base class that do all the hard work + */ + class Private_Impl + { + /** Struct used to pass information in encoder port userdata to callback + */ + struct PORT_USERDATA + { + PORT_USERDATA() { + wantToGrab=false; + pstate=0; + } + void waitForFrame() { + //_mutex.lock(); + std::unique_lock lck ( _mutex ); + + wantToGrab=true; +// _mutex.unlock(); +// Thcond.Wait(); + Thcond.Wait(lck); //this will unlock the mutex and wait atomically + }; + + + + RASPIVID_STATE *pstate; /// pointer to our state in case required in callback + std::mutex _mutex; + ThreadCondition Thcond; + bool wantToGrab; + membuf _buffData; + }; + + public: + + /**Constructor + */ + Private_Impl(); + /**Destructor + */ + ~Private_Impl(); + /**Opens the camera and start capturing + */ + bool open ( bool StartCapture=true ); + /**indicates if camera is open + */ + bool isOpened() const + { + return _isOpened; + } + /**Starts camera capture + */ + bool startCapture(); + /**Indicates if is capturing + */ + bool isCapturing() const{return _isCapturing;} + /**Grabs the next frame and keeps it in internal buffer. Blocks until next frame arrives + */ + bool grab(); + /**Retrieves the buffer previously grabbed. + * NOTE: Change in version 0.0.5. Format is stablished in setFormat function + * So type param is ignored. Do not use this parameter. + * You can use getFormat to know the current format + */ + void retrieve ( unsigned char *data,RASPICAM_FORMAT type=RASPICAM_FORMAT_IGNORE ); + /**Alternative to retrieve. Returns a pointer to the original image data buffer. + * Be careful, if you call grab(), this will be rewritten with the new data + */ + unsigned char *getImageBufferData() const; + /** + * Returns the size of the buffer returned in getImagePtr. If is like calling getImageTypeSize(getFormat()). Just for dummies :P + */ + size_t getImageBufferSize() const; + + /** Stops camera and free resources + */ + void release(); + + //sets capture format. Can not be changed once camera is opened + void setFormat ( RASPICAM_FORMAT fmt ); + void setWidth ( unsigned int width ) ; + void setHeight ( unsigned int height ); + void setCaptureSize ( unsigned int width, unsigned int height ); + void setBrightness ( unsigned int brightness ); + void setRotation ( int rotation ); + void setISO ( int iso ); + void setSharpness ( int sharpness ); + void setContrast ( int contrast ); + void setSaturation ( int saturation ); + void setExposure ( RASPICAM_EXPOSURE exposure ); + void setVideoStabilization ( bool v ); + void setExposureCompensation ( int val ); //-10,10 + void setAWB ( RASPICAM_AWB awb ); + void setAWB_RB ( float red,float blue );//ranges [0,1] + + void setImageEffect ( RASPICAM_IMAGE_EFFECT imageEffect ); + void setMetering ( RASPICAM_METERING metering ); + void setHorizontalFlip ( bool hFlip ); + void setVerticalFlip ( bool vFlip ); + /** + *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. + */ + void setShutterSpeed ( unsigned int shutter ); //currently not supported + + RASPICAM_FORMAT getFormat() const {return State.captureFtm;} + //Accessors + unsigned int getWidth() const + { + return State.width; + } + unsigned int getHeight() const + { + return State.height; + } + unsigned int getBrightness() const + { + return State.brightness; + } + unsigned int getRotation() const + { + return State.rotation; + } + int getISO() const + { + return State.ISO; + } + int getSharpness() const + { + return State.sharpness; + } + int getContrast() const + { + return State.contrast; + } + int getSaturation() const + { + return State.saturation; + } + int getShutterSpeed() const + { + return State.shutterSpeed; + } + RASPICAM_EXPOSURE getExposure() const + { + return State.rpc_exposureMode; + } + RASPICAM_AWB getAWB() const + { + return State.rpc_awbMode; + } + + float getAWBG_red(){return State.awbg_red;} + + float getAWBG_blue(){return State.awbg_blue;} + + RASPICAM_IMAGE_EFFECT getImageEffect() const + { + return State.rpc_imageEffect; + } + RASPICAM_METERING getMetering() const + { + return State.rpc_exposureMeterMode; + } + bool isHorizontallyFlipped() const + { + return State.hflip; + } + bool isVerticallyFlipped() const + { + return State.vflip; + } + + + //Returns an id of the camera. We assume the camera id is the one of the raspberry + //the id is obtained using raspberry serial number obtained in /proc/cpuinfo + std::string getId() const; + + /**Returns the size of the required buffer for the different image types in retrieve + */ + size_t getImageTypeSize ( RASPICAM_FORMAT type ) const; + + private: + static void video_buffer_callback ( MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer ); + void setDefaultStateParams(); + MMAL_COMPONENT_T *create_camera_component ( RASPIVID_STATE *state ); + void destroy_camera_component ( RASPIVID_STATE *state ); + + + //Commit + void commitParameters( ); + void commitBrightness(); + void commitRotation() ; + void commitISO() ; + void commitSharpness(); + void commitContrast(); + void commitSaturation(); + void commitExposure(); + void commitAWB(); + void commitImageEffect(); + void commitMetering(); + void commitFlips(); + void commitExposureCompensation(); + void commitVideoStabilization(); + void commitShutterSpeed(); + void commitAWB_RB(); + + MMAL_PARAM_EXPOSUREMODE_T convertExposure ( RASPICAM_EXPOSURE exposure ) ; + MMAL_PARAM_AWBMODE_T convertAWB ( RASPICAM_AWB awb ) ; + MMAL_PARAM_IMAGEFX_T convertImageEffect ( RASPICAM_IMAGE_EFFECT imageEffect ) ; + MMAL_PARAM_EXPOSUREMETERINGMODE_T convertMetering ( RASPICAM_METERING metering ) ; + int convertFormat ( RASPICAM_FORMAT fmt ) ; + + + //Color conversion + void convertBGR2RGB(unsigned char * in_bgr,unsigned char * out_rgb,int size); + float VIDEO_FRAME_RATE_NUM; + RASPIVID_STATE State; + MMAL_STATUS_T status; + MMAL_PORT_T *camera_video_port;//,*camera_still_port + PORT_USERDATA callback_data; + bool _isOpened; + bool _isCapturing; + + + }; + }; +}; + +#endif + + diff --git a/external_src/raspicam-0.1.3/src/private/private_types.h b/external_src/raspicam-0.1.3/src/private/private_types.h new file mode 100644 index 0000000..07d1a98 --- /dev/null +++ b/external_src/raspicam-0.1.3/src/private/private_types.h @@ -0,0 +1,116 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 _RaspiCam_private_types_H +#define _RaspiCam_private_types_H + +namespace raspicam { + namespace _private{ + + + /// struct contain camera settings + struct MMAL_PARAM_COLOURFX_T + { + int enable,u,v; /// Turn colourFX on or off, U and V to use + } ; + struct PARAM_FLOAT_RECT_T + { + double x,y,w,h; + } ; + + + /** Structure containing all state information for the current run + */ + struct RASPIVID_STATE + { + int width; /// Requested width of image + int height; /// requested height of image + int framerate; /// Requested frame rate (fps) + /// the camera output or the encoder output (with compression artifacts) + MMAL_COMPONENT_T *camera_component; /// Pointer to the camera component + MMAL_POOL_T *video_pool; /// Pointer to the pool of buffers used by encoder output port + //camera params + 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? + bool videoStabilisation; /// 0 or 1 (false or true) + int exposureCompensation; /// -10 to +10 ? + int shutterSpeed; + RASPICAM_FORMAT captureFtm; + RASPICAM_EXPOSURE rpc_exposureMode; + RASPICAM_METERING rpc_exposureMeterMode; + RASPICAM_AWB rpc_awbMode; + RASPICAM_IMAGE_EFFECT rpc_imageEffect; + MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imageEffectsParameters; + MMAL_PARAM_COLOURFX_T colourEffects; + 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 + float awbg_red;//white balance red and blue + float awbg_blue; + } ; + + //clean buffer + template + class membuf{ + public: + membuf() { + data=0; + size=0; + } + ~membuf() { + if ( data!=0 ) delete []data; + } + void resize ( size_t s ) { + if ( s!=size ) { + delete data; + size=s; + data=new T[size]; + } + } + T *data; + size_t size; + }; + + }; +} + +#endif + diff --git a/external_src/raspicam-0.1.3/src/private/threadcondition.cpp b/external_src/raspicam-0.1.3/src/private/threadcondition.cpp new file mode 100644 index 0000000..20e0a63 --- /dev/null +++ b/external_src/raspicam-0.1.3/src/private/threadcondition.cpp @@ -0,0 +1,72 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 "threadcondition.h" + +namespace raspicam { + namespace _private + { +//////////////////////////////// +// +//////////////////////////////// + ThreadCondition::ThreadCondition() throw ( raspicam::Exception ) { + ready=false; + } + +//////////////////////////////// +// +// +//////////////////////////////// + void ThreadCondition::Wait(std::unique_lock& lck) throw ( raspicam::Exception ) { + ready=false; + while ( !ready ) cv.wait ( lck ); + } + +//////////////////////////////// +// +// +//////////////////////////////// + void ThreadCondition::BroadCast() throw ( raspicam::Exception ) { + ready = true; + cv.notify_all(); + + } + } /* ----- end of namespace gu ----- */ + +} diff --git a/external_src/raspicam-0.1.3/src/private/threadcondition.h b/external_src/raspicam-0.1.3/src/private/threadcondition.h new file mode 100644 index 0000000..47a1a55 --- /dev/null +++ b/external_src/raspicam-0.1.3/src/private/threadcondition.h @@ -0,0 +1,74 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 _RASPICAM_THREADTHREADCONDITION_H +#define _RASPICAM_THREADTHREADCONDITION_H +#include +#include // std::thread +#include // std::mutex, std::unique_lock +#include // std::condition_variable + +#include "exceptions.h" +namespace raspicam { + namespace _private + { + /** @brief This class implements a condition to stop a thread until the + * condition is reached. + * @ingroup threads */ + class ThreadCondition + { + public: + ThreadCondition() throw ( raspicam::Exception ); + + /**The thread that call this function waits untils the condition is activated */ + void Wait(std::unique_lock& lck) throw ( raspicam::Exception ); + + + /**Wake up all threads waiting for this condition */ + void BroadCast() throw ( raspicam::Exception ); + + private: + std::mutex mtx; + std::condition_variable cv; + bool ready ; + + }; + } +} /* ----- end of namespace gu ----- */ +#endif diff --git a/external_src/raspicam-0.1.3/src/private_still/private_still_impl.cpp b/external_src/raspicam-0.1.3/src/private_still/private_still_impl.cpp new file mode 100644 index 0000000..b27cfed --- /dev/null +++ b/external_src/raspicam-0.1.3/src/private_still/private_still_impl.cpp @@ -0,0 +1,850 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 +#include "private_still_impl.h" +#include "mmal/mmal_buffer.h" +#include "mmal/util/mmal_default_components.h" +#include "mmal/util/mmal_util.h" +#include "mmal/util/mmal_util_params.h" +#include +#include +using namespace std; +namespace raspicam { + namespace _private + { + typedef struct { + Private_Impl_Still * cameraBoard; + MMAL_POOL_T * encoderPool; + imageTakenCallback imageCallback; + sem_t *mutex; + unsigned char * data; + unsigned int bufferPosition; + unsigned int startingOffset; + unsigned int offset; + unsigned int length; + } RASPICAM_USERDATA; + + static void control_callback ( MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer ) { + if ( buffer->cmd == MMAL_EVENT_PARAMETER_CHANGED ) { + } else { + // Unexpected control callback event! + } + mmal_buffer_header_release ( buffer ); + } + + static void buffer_callback ( MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer ) { + RASPICAM_USERDATA *userdata = ( RASPICAM_USERDATA* ) port->userdata; + if ( userdata == NULL || userdata->cameraBoard == NULL ) { + + } else { + unsigned int flags = buffer->flags; + mmal_buffer_header_mem_lock ( buffer ); + for ( unsigned int i = 0; i < buffer->length; i++, userdata->bufferPosition++ ) { + if ( userdata->offset >= userdata->length ) { + cout << userdata->cameraBoard->API_NAME << ": Buffer provided was too small! Failed to copy data into buffer.\n"; + userdata->cameraBoard = NULL; + break; + } else { + if ( userdata->cameraBoard->getEncoding() == RASPICAM_ENCODING_RGB ) { + // Determines if the byte is an RGB value + if ( userdata->bufferPosition >= 54 ) { + userdata->data[userdata->offset] = buffer->data[i]; + userdata->offset++; + } + } else { + userdata->data[userdata->offset] = buffer->data[i]; + userdata->offset++; + } + } + } + mmal_buffer_header_mem_unlock ( buffer ); + unsigned int END_FLAG = 0; + END_FLAG |= MMAL_BUFFER_HEADER_FLAG_FRAME_END; + END_FLAG |= MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED; + END_FLAG &= flags; + if ( END_FLAG != 0 ) { + if ( userdata->mutex == NULL ) { + userdata->imageCallback ( userdata->data, userdata->startingOffset, userdata->length - userdata->startingOffset ); + } else { + sem_post ( userdata->mutex ); + } + } + } + mmal_buffer_header_release ( buffer ); + if ( port->is_enabled ) { + MMAL_BUFFER_HEADER_T *new_buffer = mmal_queue_get ( userdata->encoderPool->queue ); + if ( new_buffer ) mmal_port_send_buffer ( port, new_buffer ); + } + } + + void Private_Impl_Still::setDefaults() { + width = 640; + height = 480; + encoding = RASPICAM_ENCODING_BMP; + encoder = NULL; + encoder_connection = NULL; + sharpness = 0; + contrast = 0; + brightness = 50; + quality = 85; + saturation = 0; + iso = 400; + //videoStabilisation = 0; + //exposureCompensation = 0; + exposure = RASPICAM_EXPOSURE_AUTO; + metering = RASPICAM_METERING_AVERAGE; + awb = RASPICAM_AWB_AUTO; + imageEffect = RASPICAM_IMAGE_EFFECT_NONE; + //colourEffects.enable = 0; + //colourEffects.u = 128; + //colourEffects.v = 128; + rotation = 0; + changedSettings = true; + horizontalFlip = false; + verticalFlip = false; + //roi.x = params->roi.y = 0.0; + //roi.w = params->roi.h = 1.0; + } + + void Private_Impl_Still::commitParameters() { + if ( !changedSettings ) return; + commitSharpness(); + commitContrast(); + commitBrightness(); + commitQuality(); + commitSaturation(); + commitISO(); + commitExposure(); + commitMetering(); + commitAWB(); + commitImageEffect(); + commitRotation(); + commitFlips(); + // Set Video Stabilization + if ( mmal_port_parameter_set_boolean ( camera->control, MMAL_PARAMETER_VIDEO_STABILISATION, 0 ) != MMAL_SUCCESS ) + cout << API_NAME << ": Failed to set video stabilization parameter.\n"; + // Set Exposure Compensation + if ( mmal_port_parameter_set_int32 ( camera->control, MMAL_PARAMETER_EXPOSURE_COMP , 0 ) != MMAL_SUCCESS ) + cout << API_NAME << ": Failed to set exposure compensation parameter.\n"; + // Set Color Efects + MMAL_PARAMETER_COLOURFX_T colfx = {{MMAL_PARAMETER_COLOUR_EFFECT,sizeof ( colfx ) }, 0, 0, 0}; + colfx.enable = 0; + colfx.u = 128; + colfx.v = 128; + if ( mmal_port_parameter_set ( camera->control, &colfx.hdr ) != MMAL_SUCCESS ) + cout << API_NAME << ": Failed to set color effects parameter.\n"; + // Set ROI + MMAL_PARAMETER_INPUT_CROP_T crop = {{MMAL_PARAMETER_INPUT_CROP, sizeof ( MMAL_PARAMETER_INPUT_CROP_T ) }}; + crop.rect.x = ( 65536 * 0 ); + crop.rect.y = ( 65536 * 0 ); + crop.rect.width = ( 65536 * 1 ); + crop.rect.height = ( 65536 * 1 ); + if ( mmal_port_parameter_set ( camera->control, &crop.hdr ) != MMAL_SUCCESS ) + cout << API_NAME << ": Failed to set ROI parameter.\n"; + // Set encoder encoding + if ( encoder_output_port != NULL ) { + encoder_output_port->format->encoding = convertEncoding ( encoding ); + mmal_port_format_commit ( encoder_output_port ); + } + changedSettings = false; + } + + MMAL_STATUS_T Private_Impl_Still::connectPorts ( MMAL_PORT_T *output_port, MMAL_PORT_T *input_port, MMAL_CONNECTION_T **connection ) { + MMAL_STATUS_T 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; + } + + int Private_Impl_Still::createCamera() { + if ( mmal_component_create ( MMAL_COMPONENT_DEFAULT_CAMERA, &camera ) ) { + cout << API_NAME << ": Failed to create camera component.\n"; + destroyCamera(); + return -1; + } + + if ( !camera->output_num ) { + cout << API_NAME << ": Camera does not have output ports!\n"; + destroyCamera(); + return -1; + } + + camera_still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT]; + + // Enable the camera, and tell it its control callback function + if ( mmal_port_enable ( camera->control, control_callback ) ) { + cout << API_NAME << ": Could not enable control port.\n"; + destroyCamera(); + return -1; + } + + MMAL_PARAMETER_CAMERA_CONFIG_T camConfig = { + {MMAL_PARAMETER_CAMERA_CONFIG, sizeof ( camConfig ) }, + width, // max_stills_w + height, // max_stills_h + 0, // stills_yuv422 + 1, // one_shot_stills + width, // max_preview_video_w + height, // max_preview_video_h + 3, // num_preview_video_frames + 0, // stills_capture_circular_buffer_height + 0, // fast_preview_resume + MMAL_PARAM_TIMESTAMP_MODE_RESET_STC // use_stc_timestamp + }; + if ( mmal_port_parameter_set ( camera->control, &camConfig.hdr ) != MMAL_SUCCESS ) + cout << API_NAME << ": Could not set port parameters.\n"; + + commitParameters(); + + MMAL_ES_FORMAT_T * format = camera_still_port->format; + format->encoding = MMAL_ENCODING_OPAQUE; + 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.num = STILLS_FRAME_RATE_NUM; + format->es->video.frame_rate.den = STILLS_FRAME_RATE_DEN; + + if ( camera_still_port->buffer_size < camera_still_port->buffer_size_min ) + camera_still_port->buffer_size = camera_still_port->buffer_size_min; + + camera_still_port->buffer_num = camera_still_port->buffer_num_recommended; + + if ( mmal_port_format_commit ( camera_still_port ) ) { + cout << API_NAME << ": Camera still format could not be set.\n"; + destroyCamera(); + return -1; + } + + if ( mmal_component_enable ( camera ) ) { + cout << API_NAME << ": Camera component could not be enabled.\n"; + destroyCamera(); + return -1; + } + + if ( ! ( encoder_pool = mmal_port_pool_create ( camera_still_port, camera_still_port->buffer_num, camera_still_port->buffer_size ) ) ) { + cout << API_NAME << ": Failed to create buffer header pool for camera.\n"; + destroyCamera(); + return -1; + } + + return 0; + } + + int Private_Impl_Still::createEncoder() { + if ( mmal_component_create ( MMAL_COMPONENT_DEFAULT_IMAGE_ENCODER, &encoder ) ) { + cout << API_NAME << ": Could not create encoder component.\n"; + destroyEncoder(); + return -1; + } + if ( !encoder->input_num || !encoder->output_num ) { + cout << API_NAME << ": Encoder does not have input/output ports.\n"; + destroyEncoder(); + return -1; + } + + encoder_input_port = encoder->input[0]; + encoder_output_port = encoder->output[0]; + + mmal_format_copy ( encoder_output_port->format, encoder_input_port->format ); + encoder_output_port->format->encoding = convertEncoding ( encoding ); // Set output encoding + encoder_output_port->buffer_size = encoder_output_port->buffer_size_recommended; + if ( encoder_output_port->buffer_size < encoder_output_port->buffer_size_min ) + encoder_output_port->buffer_size = encoder_output_port->buffer_size_min; + encoder_output_port->buffer_num = encoder_output_port->buffer_num_recommended; + if ( encoder_output_port->buffer_num < encoder_output_port->buffer_num_min ) + encoder_output_port->buffer_num = encoder_output_port->buffer_num_min; + + if ( mmal_port_format_commit ( encoder_output_port ) ) { + cout << API_NAME << ": Could not set format on encoder output port.\n"; + destroyEncoder(); + return -1; + } + if ( mmal_component_enable ( encoder ) ) { + cout << API_NAME << ": Could not enable encoder component.\n"; + destroyEncoder(); + return -1; + } + if ( ! ( encoder_pool = mmal_port_pool_create ( encoder_output_port, encoder_output_port->buffer_num, encoder_output_port->buffer_size ) ) ) { + cout << API_NAME << ": Failed to create buffer header pool for encoder output port.\n"; + destroyEncoder(); + return -1; + } + return 0; + } + + void Private_Impl_Still::destroyCamera() { + if ( camera ) { + mmal_component_destroy ( camera ); + camera = NULL; + } + } + + void Private_Impl_Still::destroyEncoder() { + if ( encoder_pool ) { + mmal_port_pool_destroy ( encoder->output[0], encoder_pool ); + } + if ( encoder ) { + mmal_component_destroy ( encoder ); + encoder = NULL; + } + } + + int Private_Impl_Still::initialize() { + if ( _isInitialized ) return 0; + if ( createCamera() ) { + cout << API_NAME << ": Failed to create camera component.\n"; + destroyCamera(); + return -1; + } else if ( createEncoder() ) { + cout << API_NAME << ": Failed to create encoder component.\n"; + destroyCamera(); + return -1; + } else { + camera_still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT]; + encoder_input_port = encoder->input[0]; + encoder_output_port = encoder->output[0]; + if ( connectPorts ( camera_still_port, encoder_input_port, &encoder_connection ) != MMAL_SUCCESS ) { + cout << "ERROR: Could not connect encoder ports!\n"; + return -1; + } + } + _isInitialized=true; + return 0; + } + + bool Private_Impl_Still::takePicture ( unsigned char * preallocated_data, unsigned int length ) { + initialize(); + int ret = 0; + sem_t mutex; + sem_init ( &mutex, 0, 0 ); + RASPICAM_USERDATA * userdata = new RASPICAM_USERDATA(); + userdata->cameraBoard = this; + userdata->encoderPool = encoder_pool; + userdata->mutex = &mutex; + userdata->data = preallocated_data; + userdata->bufferPosition = 0; + userdata->offset = 0; + userdata->startingOffset = 0; + userdata->length = length; + userdata->imageCallback = NULL; + encoder_output_port->userdata = ( struct MMAL_PORT_USERDATA_T * ) userdata; + if ( ( ret = startCapture() ) != 0 ) { + delete userdata; + return false; + } + sem_wait ( &mutex ); + sem_destroy ( &mutex ); + stopCapture(); + delete userdata; + + return true; + } + + size_t Private_Impl_Still::getImageBufferSize() const{ + return width*height*3+54 ;//oversize the buffer so to fit BMP images + } + + int Private_Impl_Still::startCapture ( imageTakenCallback userCallback, unsigned char * preallocated_data, unsigned int offset, unsigned int length ) { + RASPICAM_USERDATA * userdata = new RASPICAM_USERDATA(); + userdata->cameraBoard = this; + userdata->encoderPool = encoder_pool; + userdata->mutex = NULL; + userdata->data = preallocated_data; + userdata->bufferPosition = 0; + userdata->offset = offset; + userdata->startingOffset = offset; + userdata->length = length; + userdata->imageCallback = userCallback; + encoder_output_port->userdata = ( struct MMAL_PORT_USERDATA_T * ) userdata; + startCapture(); + } + + int Private_Impl_Still::startCapture() { + // If the parameters were changed and this function wasn't called, it will be called here + // However if the parameters weren't changed, the function won't do anything - it will return right away + commitParameters(); + + if ( encoder_output_port->is_enabled ) { + cout << API_NAME << ": Could not enable encoder output port. Try waiting longer before attempting to take another picture.\n"; + return -1; + } + if ( mmal_port_enable ( encoder_output_port, buffer_callback ) != MMAL_SUCCESS ) { + cout << API_NAME << ": Could not enable encoder output port.\n"; + return -1; + } + int num = mmal_queue_length ( encoder_pool->queue ); + for ( int b = 0; b < num; b++ ) { + MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get ( encoder_pool->queue ); + + if ( !buffer ) + cout << API_NAME << ": Could not get buffer (#" << b << ") from pool queue.\n"; + + if ( mmal_port_send_buffer ( encoder_output_port, buffer ) != MMAL_SUCCESS ) + cout << API_NAME << ": Could not send a buffer (#" << b << ") to encoder output port.\n"; + } + if ( mmal_port_parameter_set_boolean ( camera_still_port, MMAL_PARAMETER_CAPTURE, 1 ) != MMAL_SUCCESS ) { + cout << API_NAME << ": Failed to start capture.\n"; + return -1; + } + return 0; + } + + void Private_Impl_Still::stopCapture() { + if ( !encoder_output_port->is_enabled ) return; + if ( mmal_port_disable ( encoder_output_port ) ) + delete ( RASPICAM_USERDATA* ) encoder_output_port->userdata; + } + + void Private_Impl_Still::setWidth ( unsigned int width ) { + this->width = width; + changedSettings = true; + } + + void Private_Impl_Still::setHeight ( unsigned int height ) { + this->height = height; + changedSettings = true; + } + + void Private_Impl_Still::setCaptureSize ( unsigned int width, unsigned int height ) { + setWidth ( width ); + setHeight ( height ); + } + + void Private_Impl_Still::setBrightness ( unsigned int brightness ) { + if ( brightness > 100 ) + brightness = brightness % 100; + this->brightness = brightness; + changedSettings = true; + } + + void Private_Impl_Still::setQuality ( unsigned int quality ) { + if ( quality > 100 ) + quality = 100; + this->quality = quality; + changedSettings = true; + } + + void Private_Impl_Still::setRotation ( int rotation ) { + while ( rotation < 0 ) + rotation += 360; + if ( rotation >= 360 ) + rotation = rotation % 360; + this->rotation = rotation; + changedSettings = true; + } + + void Private_Impl_Still::setISO ( int iso ) { + this->iso = iso; + changedSettings = true; + } + + void Private_Impl_Still::setSharpness ( int sharpness ) { + if ( sharpness < -100 ) sharpness = -100; + if ( sharpness > 100 ) sharpness = 100; + this->sharpness = sharpness; + changedSettings = true; + } + + void Private_Impl_Still::setContrast ( int contrast ) { + if ( contrast < -100 ) contrast = -100; + if ( contrast > 100 ) contrast = 100; + this->contrast = contrast; + changedSettings = true; + } + + void Private_Impl_Still::setSaturation ( int saturation ) { + if ( saturation < -100 ) saturation = -100; + if ( saturation > 100 ) saturation = 100; + this->saturation = saturation; + changedSettings = true; + } + + void Private_Impl_Still::setEncoding ( RASPICAM_ENCODING encoding ) { + this->encoding = encoding; + changedSettings = true; + } + + void Private_Impl_Still::setExposure ( RASPICAM_EXPOSURE exposure ) { + this->exposure = exposure; + changedSettings = true; + } + + void Private_Impl_Still::setAWB ( RASPICAM_AWB awb ) { + this->awb = awb; + changedSettings = true; + } + + void Private_Impl_Still::setImageEffect ( RASPICAM_IMAGE_EFFECT imageEffect ) { + this->imageEffect = imageEffect; + changedSettings = true; + } + + void Private_Impl_Still::setMetering ( RASPICAM_METERING metering ) { + this->metering = metering; + changedSettings = true; + } + + void Private_Impl_Still::setHorizontalFlip ( bool hFlip ) { + horizontalFlip = hFlip; + changedSettings = true; + } + + void Private_Impl_Still::setVerticalFlip ( bool vFlip ) { + verticalFlip = vFlip; + changedSettings = true; + } + + unsigned int Private_Impl_Still::getWidth() { + return width; + } + + unsigned int Private_Impl_Still::getHeight() { + return height; + } + + unsigned int Private_Impl_Still::getBrightness() { + return brightness; + } + + unsigned int Private_Impl_Still::getRotation() { + return rotation; + } + + unsigned int Private_Impl_Still::getQuality() { + return quality; + } + + int Private_Impl_Still::getISO() { + return iso; + } + + int Private_Impl_Still::getSharpness() { + return sharpness; + } + + int Private_Impl_Still::getContrast() { + return contrast; + } + + int Private_Impl_Still::getSaturation() { + return saturation; + } + + RASPICAM_ENCODING Private_Impl_Still::getEncoding() { + return encoding; + } + + RASPICAM_EXPOSURE Private_Impl_Still::getExposure() { + return exposure; + } + + RASPICAM_AWB Private_Impl_Still::getAWB() { + return awb; + } + + RASPICAM_IMAGE_EFFECT Private_Impl_Still::getImageEffect() { + return imageEffect; + } + + RASPICAM_METERING Private_Impl_Still::getMetering() { + return metering; + } + + bool Private_Impl_Still::isHorizontallyFlipped() { + return horizontalFlip; + } + + bool Private_Impl_Still::isVerticallyFlipped() { + return verticalFlip; + } + + void Private_Impl_Still::commitBrightness() { + mmal_port_parameter_set_rational ( camera->control, MMAL_PARAMETER_BRIGHTNESS, ( MMAL_RATIONAL_T ) { + brightness, 100 + } ); + } + + void Private_Impl_Still::commitQuality() { + if ( encoder_output_port != NULL ) + mmal_port_parameter_set_uint32 ( encoder_output_port, MMAL_PARAMETER_JPEG_Q_FACTOR, quality ); + } + + void Private_Impl_Still::commitRotation() { + int rotation = int ( this->rotation / 90 ) * 90; + mmal_port_parameter_set_int32 ( camera->output[0], MMAL_PARAMETER_ROTATION, rotation ); + mmal_port_parameter_set_int32 ( camera->output[1], MMAL_PARAMETER_ROTATION, rotation ); + mmal_port_parameter_set_int32 ( camera->output[2], MMAL_PARAMETER_ROTATION, rotation ); + } + + void Private_Impl_Still::commitISO() { + if ( mmal_port_parameter_set_uint32 ( camera->control, MMAL_PARAMETER_ISO, iso ) != MMAL_SUCCESS ) + cout << API_NAME << ": Failed to set ISO parameter.\n"; + } + + void Private_Impl_Still::commitSharpness() { + if ( mmal_port_parameter_set_rational ( camera->control, MMAL_PARAMETER_SHARPNESS, ( MMAL_RATIONAL_T ) { + sharpness, 100 + } ) != MMAL_SUCCESS ) + cout << API_NAME << ": Failed to set sharpness parameter.\n"; + } + + void Private_Impl_Still::commitContrast() { + if ( mmal_port_parameter_set_rational ( camera->control, MMAL_PARAMETER_CONTRAST, ( MMAL_RATIONAL_T ) { + contrast, 100 + } ) != MMAL_SUCCESS ) + cout << API_NAME << ": Failed to set contrast parameter.\n"; + } + + void Private_Impl_Still::commitSaturation() { + if ( mmal_port_parameter_set_rational ( camera->control, MMAL_PARAMETER_SATURATION, ( MMAL_RATIONAL_T ) { + saturation, 100 + } ) != MMAL_SUCCESS ) + cout << API_NAME << ": Failed to set saturation parameter.\n"; + } + + void Private_Impl_Still::commitExposure() { + MMAL_PARAMETER_EXPOSUREMODE_T exp_mode = {{MMAL_PARAMETER_EXPOSURE_MODE,sizeof ( exp_mode ) }, convertExposure ( exposure ) }; + if ( mmal_port_parameter_set ( camera->control, &exp_mode.hdr ) != MMAL_SUCCESS ) + cout << API_NAME << ": Failed to set exposure parameter.\n"; + } + + void Private_Impl_Still::commitAWB() { + MMAL_PARAMETER_AWBMODE_T param = {{MMAL_PARAMETER_AWB_MODE,sizeof ( param ) }, convertAWB ( awb ) }; + if ( mmal_port_parameter_set ( camera->control, ¶m.hdr ) != MMAL_SUCCESS ) + cout << API_NAME << ": Failed to set AWB parameter.\n"; + } + + void Private_Impl_Still::commitImageEffect() { + MMAL_PARAMETER_IMAGEFX_T imgFX = {{MMAL_PARAMETER_IMAGE_EFFECT,sizeof ( imgFX ) }, convertImageEffect ( imageEffect ) }; + if ( mmal_port_parameter_set ( camera->control, &imgFX.hdr ) != MMAL_SUCCESS ) + cout << API_NAME << ": Failed to set image effect parameter.\n"; + } + + void Private_Impl_Still::commitMetering() { + MMAL_PARAMETER_EXPOSUREMETERINGMODE_T meter_mode = {{MMAL_PARAMETER_EXP_METERING_MODE, sizeof ( meter_mode ) }, convertMetering ( metering ) }; + if ( mmal_port_parameter_set ( camera->control, &meter_mode.hdr ) != MMAL_SUCCESS ) + cout << API_NAME << ": Failed to set metering parameter.\n"; + } + + void Private_Impl_Still::commitFlips() { + MMAL_PARAMETER_MIRROR_T mirror = {{MMAL_PARAMETER_MIRROR, sizeof ( MMAL_PARAMETER_MIRROR_T ) }, MMAL_PARAM_MIRROR_NONE}; + if ( horizontalFlip && verticalFlip ) + mirror.value = MMAL_PARAM_MIRROR_BOTH; + else if ( horizontalFlip ) + mirror.value = MMAL_PARAM_MIRROR_HORIZONTAL; + else if ( verticalFlip ) + mirror.value = MMAL_PARAM_MIRROR_VERTICAL; + if ( mmal_port_parameter_set ( camera->output[0], &mirror.hdr ) != MMAL_SUCCESS || + mmal_port_parameter_set ( camera->output[1], &mirror.hdr ) != MMAL_SUCCESS || + mmal_port_parameter_set ( camera->output[2], &mirror.hdr ) ) + cout << API_NAME << ": Failed to set horizontal/vertical flip parameter.\n"; + } + + MMAL_FOURCC_T Private_Impl_Still::convertEncoding ( RASPICAM_ENCODING encoding ) { + switch ( encoding ) { + case RASPICAM_ENCODING_JPEG: + return MMAL_ENCODING_JPEG; + case RASPICAM_ENCODING_BMP: + return MMAL_ENCODING_BMP; + case RASPICAM_ENCODING_GIF: + return MMAL_ENCODING_GIF; + case RASPICAM_ENCODING_PNG: + return MMAL_ENCODING_PNG; + case RASPICAM_ENCODING_RGB: + return MMAL_ENCODING_BMP; + default: + return -1; + } + } + + MMAL_PARAM_EXPOSUREMETERINGMODE_T Private_Impl_Still::convertMetering ( RASPICAM_METERING metering ) { + switch ( metering ) { + case RASPICAM_METERING_AVERAGE: + return MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE; + case RASPICAM_METERING_SPOT: + return MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT; + case RASPICAM_METERING_BACKLIT: + return MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT; + case RASPICAM_METERING_MATRIX: + return MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX; + default: + return MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE; + } + } + + MMAL_PARAM_EXPOSUREMODE_T Private_Impl_Still::convertExposure ( RASPICAM_EXPOSURE exposure ) { + switch ( exposure ) { + case RASPICAM_EXPOSURE_OFF: + return MMAL_PARAM_EXPOSUREMODE_OFF; + case RASPICAM_EXPOSURE_AUTO: + return MMAL_PARAM_EXPOSUREMODE_AUTO; + case RASPICAM_EXPOSURE_NIGHT: + return MMAL_PARAM_EXPOSUREMODE_NIGHT; + case RASPICAM_EXPOSURE_NIGHTPREVIEW: + return MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW; + case RASPICAM_EXPOSURE_BACKLIGHT: + return MMAL_PARAM_EXPOSUREMODE_BACKLIGHT; + case RASPICAM_EXPOSURE_SPOTLIGHT: + return MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT; + case RASPICAM_EXPOSURE_SPORTS: + return MMAL_PARAM_EXPOSUREMODE_SPORTS; + case RASPICAM_EXPOSURE_SNOW: + return MMAL_PARAM_EXPOSUREMODE_SNOW; + case RASPICAM_EXPOSURE_BEACH: + return MMAL_PARAM_EXPOSUREMODE_BEACH; + case RASPICAM_EXPOSURE_VERYLONG: + return MMAL_PARAM_EXPOSUREMODE_VERYLONG; + case RASPICAM_EXPOSURE_FIXEDFPS: + return MMAL_PARAM_EXPOSUREMODE_FIXEDFPS; + case RASPICAM_EXPOSURE_ANTISHAKE: + return MMAL_PARAM_EXPOSUREMODE_ANTISHAKE; + case RASPICAM_EXPOSURE_FIREWORKS: + return MMAL_PARAM_EXPOSUREMODE_FIREWORKS; + default: + return MMAL_PARAM_EXPOSUREMODE_AUTO; + } + } + + MMAL_PARAM_AWBMODE_T Private_Impl_Still::convertAWB ( RASPICAM_AWB awb ) { + switch ( awb ) { + case RASPICAM_AWB_OFF: + return MMAL_PARAM_AWBMODE_OFF; + case RASPICAM_AWB_AUTO: + return MMAL_PARAM_AWBMODE_AUTO; + case RASPICAM_AWB_SUNLIGHT: + return MMAL_PARAM_AWBMODE_SUNLIGHT; + case RASPICAM_AWB_CLOUDY: + return MMAL_PARAM_AWBMODE_CLOUDY; + case RASPICAM_AWB_SHADE: + return MMAL_PARAM_AWBMODE_SHADE; + case RASPICAM_AWB_TUNGSTEN: + return MMAL_PARAM_AWBMODE_TUNGSTEN; + case RASPICAM_AWB_FLUORESCENT: + return MMAL_PARAM_AWBMODE_FLUORESCENT; + case RASPICAM_AWB_INCANDESCENT: + return MMAL_PARAM_AWBMODE_INCANDESCENT; + case RASPICAM_AWB_FLASH: + return MMAL_PARAM_AWBMODE_FLASH; + case RASPICAM_AWB_HORIZON: + return MMAL_PARAM_AWBMODE_HORIZON; + default: + return MMAL_PARAM_AWBMODE_AUTO; + } + } + + MMAL_PARAM_IMAGEFX_T Private_Impl_Still::convertImageEffect ( RASPICAM_IMAGE_EFFECT imageEffect ) { + switch ( imageEffect ) { + case RASPICAM_IMAGE_EFFECT_NONE: + return MMAL_PARAM_IMAGEFX_NONE; + case RASPICAM_IMAGE_EFFECT_NEGATIVE: + return MMAL_PARAM_IMAGEFX_NEGATIVE; + case RASPICAM_IMAGE_EFFECT_SOLARIZE: + return MMAL_PARAM_IMAGEFX_SOLARIZE; + case RASPICAM_IMAGE_EFFECT_SKETCH: + return MMAL_PARAM_IMAGEFX_SKETCH; + case RASPICAM_IMAGE_EFFECT_DENOISE: + return MMAL_PARAM_IMAGEFX_DENOISE; + case RASPICAM_IMAGE_EFFECT_EMBOSS: + return MMAL_PARAM_IMAGEFX_EMBOSS; + case RASPICAM_IMAGE_EFFECT_OILPAINT: + return MMAL_PARAM_IMAGEFX_OILPAINT; + case RASPICAM_IMAGE_EFFECT_HATCH: + return MMAL_PARAM_IMAGEFX_HATCH; + case RASPICAM_IMAGE_EFFECT_GPEN: + return MMAL_PARAM_IMAGEFX_GPEN; + case RASPICAM_IMAGE_EFFECT_PASTEL: + return MMAL_PARAM_IMAGEFX_PASTEL; + case RASPICAM_IMAGE_EFFECT_WATERCOLOR: + return MMAL_PARAM_IMAGEFX_WATERCOLOUR; + case RASPICAM_IMAGE_EFFECT_FILM: + return MMAL_PARAM_IMAGEFX_FILM; + case RASPICAM_IMAGE_EFFECT_BLUR: + return MMAL_PARAM_IMAGEFX_BLUR; + case RASPICAM_IMAGE_EFFECT_SATURATION: + return MMAL_PARAM_IMAGEFX_SATURATION; + case RASPICAM_IMAGE_EFFECT_COLORSWAP: + return MMAL_PARAM_IMAGEFX_COLOURSWAP; + case RASPICAM_IMAGE_EFFECT_WASHEDOUT: + return MMAL_PARAM_IMAGEFX_WASHEDOUT; + case RASPICAM_IMAGE_EFFECT_POSTERISE: + return MMAL_PARAM_IMAGEFX_POSTERISE; + case RASPICAM_IMAGE_EFFECT_COLORPOINT: + return MMAL_PARAM_IMAGEFX_COLOURPOINT; + case RASPICAM_IMAGE_EFFECT_COLORBALANCE: + return MMAL_PARAM_IMAGEFX_COLOURBALANCE; + case RASPICAM_IMAGE_EFFECT_CARTOON: + return MMAL_PARAM_IMAGEFX_CARTOON; + } + } + + //Returns an id of the camera. We assume the camera id is the one of the raspberry + //the id is obtained using raspberry serial number obtained in /proc/cpuinfo + string Private_Impl_Still::getId() const{ + char serial[1024]; + serial[0]='\0'; + ifstream file ( "/proc/cpuinfo" ); + if ( !file ) { + cerr<<__FILE__<<" "<<__LINE__<<":"<<__func__<<"Could not read /proc/cpuinfo"< +#define MMAL_CAMERA_CAPTURE_PORT 2 +#define STILLS_FRAME_RATE_NUM 3 +#define STILLS_FRAME_RATE_DEN 1 +namespace raspicam { + namespace _private + { + typedef void ( *imageTakenCallback ) ( unsigned char * data, unsigned int image_offset, unsigned int length ); + + class Private_Impl_Still { + + private: + + MMAL_COMPONENT_T * camera; /// Pointer to the camera component + MMAL_COMPONENT_T * encoder; /// Pointer to the encoder component + MMAL_CONNECTION_T * encoder_connection; // Connection from the camera to the encoder + MMAL_POOL_T * encoder_pool; /// Pointer to the pool of buffers used by encoder output port + MMAL_PORT_T * camera_still_port; + MMAL_PORT_T * encoder_input_port; + MMAL_PORT_T * encoder_output_port; + unsigned int width; + unsigned int height; + unsigned int rotation; // 0 to 359 + unsigned int brightness; // 0 to 100 + unsigned int quality; // 0 to 100 + int iso; + int sharpness; // -100 to 100 + int contrast; // -100 to 100 + int saturation; // -100 to 100 + RASPICAM_ENCODING encoding; + RASPICAM_EXPOSURE exposure; + RASPICAM_AWB awb; + RASPICAM_IMAGE_EFFECT imageEffect; + RASPICAM_METERING metering; + bool changedSettings; + bool horizontalFlip; + bool verticalFlip; + + MMAL_FOURCC_T convertEncoding ( RASPICAM_ENCODING encoding ); + MMAL_PARAM_EXPOSUREMETERINGMODE_T convertMetering ( RASPICAM_METERING metering ); + MMAL_PARAM_EXPOSUREMODE_T convertExposure ( RASPICAM_EXPOSURE exposure ); + MMAL_PARAM_AWBMODE_T convertAWB ( RASPICAM_AWB awb ); + MMAL_PARAM_IMAGEFX_T convertImageEffect ( RASPICAM_IMAGE_EFFECT imageEffect ); + void commitBrightness(); + void commitQuality(); + void commitRotation(); + void commitISO(); + void commitSharpness(); + void commitContrast(); + void commitSaturation(); + void commitExposure(); + void commitAWB(); + void commitImageEffect(); + void commitMetering(); + void commitFlips(); + int startCapture(); + int createCamera(); + int createEncoder(); + void destroyCamera(); + void destroyEncoder(); + void setDefaults(); + MMAL_STATUS_T connectPorts ( MMAL_PORT_T *output_port, MMAL_PORT_T *input_port, MMAL_CONNECTION_T **connection ); + + bool _isInitialized; + public: + const char * API_NAME; + Private_Impl_Still() { + API_NAME = "Private_Impl_Still"; + setDefaults(); + camera = NULL; + encoder = NULL; + encoder_connection = NULL; + encoder_pool = NULL; + camera_still_port = NULL; + encoder_input_port = NULL; + encoder_output_port = NULL; + _isInitialized=false; + } + int initialize(); + int startCapture ( imageTakenCallback userCallback, unsigned char * preallocated_data, unsigned int offset, unsigned int length ); + void stopCapture(); + bool takePicture ( unsigned char * preallocated_data, unsigned int length ); + + size_t getImageBufferSize() const; + void bufferCallback ( MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer ); + void commitParameters(); + void setWidth ( unsigned int width ); + void setHeight ( unsigned int height ); + void setCaptureSize ( unsigned int width, unsigned int height ); + void setBrightness ( unsigned int brightness ); + void setQuality ( unsigned int quality ); + void setRotation ( int rotation ); + void setISO ( int iso ); + void setSharpness ( int sharpness ); + void setContrast ( int contrast ); + void setSaturation ( int saturation ); + void setEncoding ( RASPICAM_ENCODING encoding ); + void setExposure ( RASPICAM_EXPOSURE exposure ); + void setAWB ( RASPICAM_AWB awb ); + void setImageEffect ( RASPICAM_IMAGE_EFFECT imageEffect ); + void setMetering ( RASPICAM_METERING metering ); + void setHorizontalFlip ( bool hFlip ); + void setVerticalFlip ( bool vFlip ); + + unsigned int getWidth(); + unsigned int getHeight(); + unsigned int getBrightness(); + unsigned int getRotation(); + unsigned int getQuality(); + int getISO(); + int getSharpness(); + int getContrast(); + int getSaturation(); + RASPICAM_ENCODING getEncoding(); + RASPICAM_EXPOSURE getExposure(); + RASPICAM_AWB getAWB(); + RASPICAM_IMAGE_EFFECT getImageEffect(); + RASPICAM_METERING getMetering(); + bool isHorizontallyFlipped(); + bool isVerticallyFlipped(); + + + //Returns an id of the camera. We assume the camera id is the one of the raspberry + //the id is obtained using raspberry serial number obtained in /proc/cpuinfo + std::string getId() const; + + }; + + } +} +#endif // RASPICAM_H diff --git a/external_src/raspicam-0.1.3/src/raspicam.cpp b/external_src/raspicam-0.1.3/src/raspicam.cpp new file mode 100644 index 0000000..52297e9 --- /dev/null +++ b/external_src/raspicam-0.1.3/src/raspicam.cpp @@ -0,0 +1,166 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 "raspicam.h" +#include "private/private_impl.h" +namespace raspicam { + + RaspiCam::RaspiCam() { + _impl=new _private::Private_Impl; + } + RaspiCam::~RaspiCam() { + delete _impl; + } + + + bool RaspiCam::open ( bool StartCapture ) { + return _impl->open ( StartCapture ); + } + bool RaspiCam::startCapture() { + return _impl->startCapture(); + } + + bool RaspiCam::isOpened() const {return _impl->isOpened();} + + bool RaspiCam::grab() { + return _impl->grab(); + } + + void RaspiCam::retrieve ( unsigned char *data,RASPICAM_FORMAT type ) { + _impl->retrieve ( data,type ); + } + unsigned char *RaspiCam::getImageBufferData() const{return _impl->getImageBufferData();} + size_t RaspiCam::getImageBufferSize() const{return _impl->getImageBufferSize();} + + size_t RaspiCam::getImageTypeSize ( RASPICAM_FORMAT type ) const{return _impl->getImageTypeSize ( type );} + + void RaspiCam::release() { + _impl->release(); + } + + void RaspiCam::setFormat(RASPICAM_FORMAT fmt){ + _impl->setFormat( fmt); + } + void RaspiCam::setWidth ( unsigned int width ) { + _impl->setWidth ( width ); + } + void RaspiCam::setHeight ( unsigned int height ) { + _impl->setHeight ( height ); + } + void RaspiCam::setCaptureSize ( unsigned int width, unsigned int height ) { + _impl->setCaptureSize ( width,height ); + } + void RaspiCam::setBrightness ( unsigned int brightness ) { + _impl->setBrightness ( brightness ); + } + void RaspiCam::setRotation ( int rotation ) { + _impl->setRotation ( rotation ); + } + void RaspiCam::setISO ( int iso ) { + _impl->setISO ( iso ); + } + void RaspiCam::setSharpness ( int sharpness ) { + _impl->setSharpness ( sharpness ); + } + void RaspiCam::setContrast ( int contrast ) { + _impl->setContrast ( contrast ); + } + void RaspiCam::setSaturation ( int saturation ) { + _impl->setSaturation ( saturation ); + } + void RaspiCam::setExposure ( RASPICAM_EXPOSURE exposure ) { + _impl->setExposure ( exposure ); + } + void RaspiCam::setShutterSpeed ( unsigned int ss ) { + _impl->setShutterSpeed ( ss ); + } + + void RaspiCam::setVideoStabilization ( bool v ) { + _impl->setVideoStabilization ( v ); + } + void RaspiCam::setExposureCompensation ( int val ) { + _impl->setExposureCompensation ( val ); + } + void RaspiCam::setAWB ( RASPICAM_AWB awb ) { + _impl->setAWB ( awb ); + } + void RaspiCam::setAWB_RB ( float r,float b ){ + _impl->setAWB_RB(r,b); + } + + void RaspiCam::setImageEffect ( RASPICAM_IMAGE_EFFECT imageEffect ) { + _impl->setImageEffect ( imageEffect ); + } + void RaspiCam::setMetering ( RASPICAM_METERING metering ) { + _impl->setMetering ( metering ); + } + void RaspiCam::setHorizontalFlip ( bool hFlip ) { + _impl->setHorizontalFlip ( hFlip ); + } + void RaspiCam::setVerticalFlip ( bool vFlip ) { + _impl->setVerticalFlip ( vFlip ); + } + + + RASPICAM_FORMAT RaspiCam::getFormat()const{return _impl->getFormat( ); } + unsigned int RaspiCam::getWidth() const{return _impl->getWidth() ;} + unsigned int RaspiCam::getHeight() const{return _impl->getHeight() ;} + unsigned int RaspiCam::getBrightness() const{return _impl->getBrightness() ;} + unsigned int RaspiCam::getRotation() const{return _impl->getRotation() ;} + int RaspiCam::getISO() const{return _impl->getISO() ;} + unsigned int RaspiCam::getShutterSpeed() const{return 150000;}//return _impl->getShutterSpeed();} + + int RaspiCam::getSharpness() const{return _impl->getSharpness() ;} + int RaspiCam::getContrast() const{return _impl->getContrast() ;} + int RaspiCam::getSaturation() const{return _impl->getSaturation() ;} + RASPICAM_EXPOSURE RaspiCam::getExposure() const {return _impl->getExposure() ;} + RASPICAM_AWB RaspiCam::getAWB() const{return _impl->getAWB() ;} + float RaspiCam::getAWBG_red()const{return _impl->getAWBG_red();} + float RaspiCam::getAWBG_blue()const{return _impl->getAWBG_blue();} + + RASPICAM_IMAGE_EFFECT RaspiCam::getImageEffect() const{return _impl->getImageEffect() ;}; + RASPICAM_METERING RaspiCam::getMetering() const{return _impl->getMetering() ;} + bool RaspiCam::isHorizontallyFlipped() const {return _impl->isHorizontallyFlipped() ;} + bool RaspiCam::isVerticallyFlipped() const {return _impl->isVerticallyFlipped() ;} + + //Returns an id of the camera. We assume the camera id is the one of the raspberry + //the id is obtained using raspberry serial number obtained in /proc/cpuinfo + std::string RaspiCam::getId() const{return _impl->getId();} + + +}; + diff --git a/external_src/raspicam-0.1.3/src/raspicam.h b/external_src/raspicam-0.1.3/src/raspicam.h new file mode 100644 index 0000000..3b601ea --- /dev/null +++ b/external_src/raspicam-0.1.3/src/raspicam.h @@ -0,0 +1,178 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 _RaspiCam_H_ +#define _RaspiCam_H_ +#include +#include +#include "raspicamtypes.h" +namespace raspicam { + + namespace _private{ + class Private_Impl; + }; + /**Base class that do all the hard work + */ + class RaspiCam + { + public: + /**Constructor + */ + RaspiCam(); + /**Destructor + */ + ~RaspiCam(); + /**Opens the camera + * @param StartCapture determines if camera must start capture or not. + */ + bool open ( bool StartCapture=true ); + /**Makes camera start capturing + */ + bool startCapture(); + /**indicates if camera is open + */ + bool isOpened() const ; + /**Grabs the next frame and keeps it in internal buffer. Blocks until next frame arrives + */ + bool grab(); + /**Retrieves the buffer previously grabbed. + * You can decide how image is given by setting type. The input buffer provided must have the appropriate + * size accordingly. You can use getImageTypeSize() to determine the size + * NOTE: Change in version 0.0.5. Format is stablished in setFormat function + * So type param is ignored. Do not use this parameter. + * You can use getFormat() to know the current format + */ + void retrieve ( unsigned char *data,RASPICAM_FORMAT type=RASPICAM_FORMAT_IGNORE ); + /**Alternative to retrieve. Returns a pointer to the original image data buffer (which is in getFormat() format). + * + * Be careful, if you call grab(), this will be rewritten with the new data + */ + unsigned char *getImageBufferData() const; + /** + * Returns the size of the images captured. + */ + size_t getImageBufferSize() const; + + + /** Stops camera and free resources + */ + void release(); + + /**Sets capture format + */ + void setFormat ( RASPICAM_FORMAT fmt ); + /**Sets camera width. Use a multiple of 320 (640, 1280) + */ + void setWidth ( unsigned int width ) ; + /**Sets camera Height. Use a multiple of 240 (480, 960) + */ + void setHeight ( unsigned int height ); + void setCaptureSize ( unsigned int width, unsigned int height ); + /** Set image brightness [0,100] + */ + void setBrightness ( unsigned int brightness ); + /** + * Set image sharpness (-100 to 100) + */ + void setSharpness ( int sharpness ); + /** + * Set image contrast (-100 to 100) + */ + void setContrast ( int contrast ); + /** + * Set capture ISO (100 to 800) + */ + void setISO ( int iso ); + /** + * Set image saturation (-100 to 100) + */ + void setSaturation ( int saturation ); + /**Sets on/off video stabilisation + */ + void setVideoStabilization ( bool v ); + /** + * Set EV compensation (-10,10) + */ + void setExposureCompensation ( int val ); //-10,10 + void setRotation ( int rotation ); + void setExposure ( RASPICAM_EXPOSURE exposure ); + void setShutterSpeed ( unsigned int ss ); + void setAWB ( RASPICAM_AWB awb ); + // et specific values for whitebalance. Requires to set seAWB in OFF mode first + void setAWB_RB ( float r,float b );//range is 0-1. + void setImageEffect ( RASPICAM_IMAGE_EFFECT imageEffect ); + void setMetering ( RASPICAM_METERING metering ); + void setHorizontalFlip ( bool hFlip ); + void setVerticalFlip ( bool vFlip ); + + //Accessors + RASPICAM_FORMAT getFormat() const; + unsigned int getWidth() const; + unsigned int getHeight() const; + unsigned int getBrightness() const; + unsigned int getRotation() const; + int getISO() const; + int getSharpness() const; + int getContrast() const; + int getSaturation() const; + unsigned int getShutterSpeed() const; + RASPICAM_EXPOSURE getExposure() const ; + RASPICAM_AWB getAWB() const; + float getAWBG_red()const; + float getAWBG_blue()const; + RASPICAM_IMAGE_EFFECT getImageEffect() const ; + RASPICAM_METERING getMetering() const; + bool isHorizontallyFlipped() const ; + bool isVerticallyFlipped() const ; + + + /** Returns an id of the camera. We assume the camera id is the one of the raspberry + *the id is obtained using raspberry serial number obtained in /proc/cpuinfo + */ + std::string getId() const; + + + + /**Returns the size of the required buffer for the different image types in retrieve + */ + size_t getImageTypeSize ( RASPICAM_FORMAT type ) const; + private: + _private::Private_Impl *_impl; + }; +}; +#endif + diff --git a/external_src/raspicam-0.1.3/src/raspicam_cv.cpp b/external_src/raspicam-0.1.3/src/raspicam_cv.cpp new file mode 100644 index 0000000..d8c0baf --- /dev/null +++ b/external_src/raspicam-0.1.3/src/raspicam_cv.cpp @@ -0,0 +1,214 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 "raspicam_cv.h" +#include "private/private_impl.h" +#include +#include +#include "scaler.h" +namespace raspicam { + RaspiCam_Cv::RaspiCam_Cv() { + _impl=new _private::Private_Impl(); + set(CV_CAP_PROP_FORMAT,CV_8UC3); + + } + RaspiCam_Cv::~RaspiCam_Cv() { + delete _impl; + } + + /** Open capturing device for video capturing + */ + bool RaspiCam_Cv::open ( void ) { + return _impl->open(); + } + /** + * Returns true if video capturing has been initialized already. + */ + bool RaspiCam_Cv::isOpened() const {return _impl->isOpened();} + /** + *Closes video file or capturing device. + */ + void RaspiCam_Cv::release() { + _impl->release(); + } + + /** + * Grabs the next frame from video file or capturing device. + */ + bool RaspiCam_Cv::grab() { + return _impl->grab(); + } + + /** + *Decodes and returns the grabbed video frame. + */ + void RaspiCam_Cv::retrieve ( cv::Mat& image ) { + //here we go! + image.create ( _impl->getHeight(),_impl->getWidth(),imgFormat ); + _impl->retrieve ( image.ptr ( 0 )); + } + + /**Returns the specified VideoCapture property + */ + + double RaspiCam_Cv::get ( int propId ) { + + switch ( propId ) { + + case CV_CAP_PROP_FRAME_WIDTH : + return _impl->getWidth(); + case CV_CAP_PROP_FRAME_HEIGHT : + return _impl->getHeight(); + case CV_CAP_PROP_FPS: + return 30; + case CV_CAP_PROP_FORMAT : + return imgFormat; + case CV_CAP_PROP_MODE : + return 0; + case CV_CAP_PROP_BRIGHTNESS : + return _impl->getBrightness(); + case CV_CAP_PROP_CONTRAST : + return Scaler::scale ( -100,100,0,100, _impl->getContrast() ); + case CV_CAP_PROP_SATURATION : + return Scaler::scale ( -100,100,0,100, _impl->getSaturation() );; +// case CV_CAP_PROP_HUE : return _cam_impl->getSharpness(); + case CV_CAP_PROP_GAIN : + return Scaler::scale ( 0,800,0,100, _impl->getISO() ); + case CV_CAP_PROP_EXPOSURE : + if ( _impl->getShutterSpeed() ==0 ) + return -1;//auto + else return Scaler::scale (0,330000, 0,100, _impl->getShutterSpeed() ) ; + break; + case CV_CAP_PROP_CONVERT_RGB : + return ( imgFormat==CV_8UC3 ); + case CV_CAP_PROP_WHITE_BALANCE_RED_V: + return _impl->getAWBG_red()*100; + break; + + case CV_CAP_PROP_WHITE_BALANCE_BLUE_U: + return _impl->getAWBG_blue()*100; + break; + default : + return -1; + }; + } + + /**Sets a property in the VideoCapture. + */ + + bool RaspiCam_Cv::set ( int propId, double value ) { + + switch ( propId ) { + + case CV_CAP_PROP_FRAME_WIDTH : + _impl->setWidth ( value ); + break; + case CV_CAP_PROP_FRAME_HEIGHT : + _impl->setHeight ( value ); + break; + case CV_CAP_PROP_FORMAT :{ + bool res=true; + if ( value==CV_8UC1 ){ + _impl->setFormat(RASPICAM_FORMAT_GRAY); + imgFormat=value; + } + else if (value==CV_8UC3){ + _impl->setFormat(RASPICAM_FORMAT_BGR); + imgFormat=value; + } + else res=false;//error int format + return res; + }break; + case CV_CAP_PROP_MODE ://nothing to do yet + return false; + break; + case CV_CAP_PROP_BRIGHTNESS : + _impl->setBrightness ( value ); + break; + case CV_CAP_PROP_CONTRAST : + _impl->setContrast ( Scaler::scale ( 0,100,-100,100, value ) ); + break; + case CV_CAP_PROP_SATURATION : + _impl->setSaturation ( Scaler::scale ( 0,100,-100,100, value ) ); + break; +// case CV_CAP_PROP_HUE : return _cam_impl->getSharpness(); + case CV_CAP_PROP_GAIN : + _impl->setISO ( Scaler::scale ( 0,100,0,800, value ) ); + break; + case CV_CAP_PROP_EXPOSURE : + if ( value>0 && value<=100 ) { + _impl->setShutterSpeed ( Scaler::scale ( 0,100,0,330000, value ) ); + } else { + _impl->setExposure ( RASPICAM_EXPOSURE_AUTO ); + _impl->setShutterSpeed ( 0 ); + } + break; + case CV_CAP_PROP_CONVERT_RGB : + imgFormat=CV_8UC3; + break; + case CV_CAP_PROP_WHITE_BALANCE_RED_V: + if (value==0) _impl->setAWB(raspicam::RASPICAM_AWB_AUTO); + else { + int valblue=_impl->getAWBG_blue()*100; + _impl->setAWB(raspicam::RASPICAM_AWB_OFF); + _impl->setAWB_RB(value*100,valblue); + }; + break; + + case CV_CAP_PROP_WHITE_BALANCE_BLUE_U: + if (value==0) _impl->setAWB(raspicam::RASPICAM_AWB_AUTO); + else { + int valred=_impl->getAWBG_red()*100; + _impl->setAWB(raspicam::RASPICAM_AWB_OFF); + _impl->setAWB_RB(valred, value*100 ); + }; + break; + +// case CV_CAP_PROP_WHITE_BALANCE :return _cam_impl->getAWB(); + default : + return false; + }; + return true; + + } + std::string RaspiCam_Cv::getId() const{ + return _impl->getId(); + } + +} + + diff --git a/external_src/raspicam-0.1.3/src/raspicam_cv.h b/external_src/raspicam-0.1.3/src/raspicam_cv.h new file mode 100644 index 0000000..fdeeef4 --- /dev/null +++ b/external_src/raspicam-0.1.3/src/raspicam_cv.h @@ -0,0 +1,115 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 RaspiCam_CV_H +#define RaspiCam_CV_H +#include +#include +namespace raspicam { + + namespace _private{ + class Private_Impl; + }; + /**Class for using Raspberry camera as in opencv + */ + class RaspiCam_Cv { + _private::Private_Impl *_impl; + public: + /**Constructor + */ + RaspiCam_Cv(); + /**Destructor + */ + ~RaspiCam_Cv(); + /** Open capturing device for video capturing + */ + bool open ( void ); + /** + * Returns true if video capturing has been initialized already. + */ + bool isOpened() const; + /** + *Closes video file or capturing device. + */ + void release(); + + /** + * Grabs the next frame from video file or capturing device. + */ + bool grab(); + + /** + *Decodes and returns the grabbed video frame. + */ + void retrieve ( cv::Mat& image ); + + /**Returns the specified VideoCapture property + */ + + double get ( int propId ); + + /**Sets a property in the VideoCapture. + * + * + * Implemented properties: + * CV_CAP_PROP_FRAME_WIDTH,CV_CAP_PROP_FRAME_HEIGHT, + * CV_CAP_PROP_FORMAT: CV_8UC1 or CV_8UC3 + * CV_CAP_PROP_BRIGHTNESS: [0,100] + * CV_CAP_PROP_CONTRAST: [0,100] + * CV_CAP_PROP_SATURATION: [0,100] + * CV_CAP_PROP_GAIN: (iso): [0,100] + * CV_CAP_PROP_EXPOSURE: -1 auto. [1,100] shutter speed from 0 to 33ms + * CV_CAP_PROP_WHITE_BALANCE_RED_V : [1,100] -1 auto whitebalance + * CV_CAP_PROP_WHITE_BALANCE_BLUE_U : [1,100] -1 auto whitebalance + * + */ + + bool set ( int propId, double value ); + + /** Returns the camera identifier. We assume the camera id is the one of the raspberry obtained using raspberry serial number obtained in /proc/cpuinfo + */ + std::string getId()const; + + private: + cv::Mat image; + int imgFormat;//required image format // + }; + +}; +#endif + + diff --git a/external_src/raspicam-0.1.3/src/raspicam_still.cpp b/external_src/raspicam-0.1.3/src/raspicam_still.cpp new file mode 100644 index 0000000..52c4b7a --- /dev/null +++ b/external_src/raspicam-0.1.3/src/raspicam_still.cpp @@ -0,0 +1,167 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 "raspicam_still.h" +#include "private_still/private_still_impl.h" +namespace raspicam { + RaspiCam_Still::RaspiCam_Still() { + _impl= new _private::Private_Impl_Still() ; + } + RaspiCam_Still::~RaspiCam_Still() { + release(); + delete _impl; + } + + + bool RaspiCam_Still::open ( ) { + return _impl->initialize() ==0; + } + bool RaspiCam_Still::grab_retrieve ( unsigned char * preallocated_data, unsigned int length ) { + return _impl->takePicture ( preallocated_data, length ); + + } + void RaspiCam_Still::release() {} + + size_t RaspiCam_Still::getImageBufferSize() const{ + return _impl-> getImageBufferSize(); + + } + void RaspiCam_Still::commitParameters() { + _impl-> commitParameters(); + } + void RaspiCam_Still::setWidth ( unsigned int width ) { + _impl-> setWidth ( width ); + } + void RaspiCam_Still::setHeight ( unsigned int height ) { + _impl->setHeight ( height ); + } + void RaspiCam_Still::setCaptureSize ( unsigned int width, unsigned int height ) { + _impl->setCaptureSize ( width,height ); + } + void RaspiCam_Still::setBrightness ( unsigned int brightness ) { + _impl->setBrightness ( brightness ); + } + void RaspiCam_Still::setQuality ( unsigned int quality ) { + _impl->setQuality ( quality ); + } + void RaspiCam_Still::setRotation ( int rotation ) { + _impl-> setRotation ( rotation ); + } + void RaspiCam_Still::setISO ( int iso ) { + _impl-> setISO ( iso ); + } + void RaspiCam_Still::setSharpness ( int sharpness ) { + _impl->setSharpness ( sharpness ); + } + void RaspiCam_Still::setContrast ( int contrast ) { + _impl->setContrast ( contrast ); + } + void RaspiCam_Still::setSaturation ( int saturation ) { + _impl->setSaturation ( saturation ); + } + void RaspiCam_Still::setEncoding ( RASPICAM_ENCODING encoding ) { + _impl->setEncoding ( encoding ); + } + void RaspiCam_Still::setExposure ( RASPICAM_EXPOSURE exposure ) { + _impl->setExposure ( exposure ); + } + void RaspiCam_Still::setAWB ( RASPICAM_AWB awb ) { + _impl->setAWB ( awb ); + } + void RaspiCam_Still::setImageEffect ( RASPICAM_IMAGE_EFFECT imageEffect ) { + _impl-> setImageEffect ( imageEffect ); + } + void RaspiCam_Still::setMetering ( RASPICAM_METERING metering ) { + _impl->setMetering ( metering ); + } + void RaspiCam_Still::setHorizontalFlip ( bool hFlip ) { + _impl->setHorizontalFlip ( hFlip ); + } + void RaspiCam_Still::setVerticalFlip ( bool vFlip ) { + _impl->setVerticalFlip ( vFlip ); + } + + unsigned int RaspiCam_Still::getWidth() { + return _impl->getWidth(); + } + unsigned int RaspiCam_Still::getHeight() { + return _impl->getHeight(); + } + unsigned int RaspiCam_Still::getBrightness() { + return _impl->getBrightness(); + } + unsigned int RaspiCam_Still::getRotation() { + return _impl->getRotation(); + } + unsigned int RaspiCam_Still::getQuality() { + return _impl->getQuality(); + } + int RaspiCam_Still::getISO() { + return _impl->getISO(); + } + int RaspiCam_Still::getSharpness() { + return _impl->getSharpness(); + } + int RaspiCam_Still::getContrast() { + return _impl->getContrast(); + } + int RaspiCam_Still::getSaturation() { + return _impl->getSaturation(); + } + RASPICAM_ENCODING RaspiCam_Still::getEncoding() { + return _impl->getEncoding(); + } + RASPICAM_EXPOSURE RaspiCam_Still::getExposure() { + return _impl->getExposure (); + } + RASPICAM_AWB RaspiCam_Still::getAWB() { + return _impl->getAWB(); + } + RASPICAM_IMAGE_EFFECT RaspiCam_Still::getImageEffect() { + return _impl->getImageEffect(); + } + RASPICAM_METERING RaspiCam_Still::getMetering() { + return _impl->getMetering(); + } + bool RaspiCam_Still::isHorizontallyFlipped() { + return _impl->isHorizontallyFlipped(); + } + bool RaspiCam_Still::isVerticallyFlipped() { + return _impl->isVerticallyFlipped(); + } +} + + diff --git a/external_src/raspicam-0.1.3/src/raspicam_still.h b/external_src/raspicam-0.1.3/src/raspicam_still.h new file mode 100644 index 0000000..5362a32 --- /dev/null +++ b/external_src/raspicam-0.1.3/src/raspicam_still.h @@ -0,0 +1,111 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 _RaspiCam_STILL_H +#define _RaspiCam_STILL_H + +#include "raspicamtypes.h" +#include +namespace raspicam { + + namespace _private{ + class Private_Impl_Still; + }; + + + /**Raspicam API for still camera + */ + class RaspiCam_Still{ + //the implementation of the camera + _private::Private_Impl_Still *_impl; + + public: + //Constructor + RaspiCam_Still(); + //Destructor + ~RaspiCam_Still(); + // Opens camera connection + bool open ( ); + //Grabs and set the data into the data buffer which has the indicated length. It is your responsability + // to alloc the buffer. You can use getImageBufferSize for that matter. + bool grab_retrieve ( unsigned char * data, unsigned int length ); + //Releases the camera + void release();//not working + // Returns the size of the images captured with the current parameters + size_t getImageBufferSize() const; + + + + void commitParameters(); + void setWidth ( unsigned int width ); + void setHeight ( unsigned int height ); + void setCaptureSize ( unsigned int width, unsigned int height ); + void setBrightness ( unsigned int brightness ); + void setQuality ( unsigned int quality ); + void setRotation ( int rotation ); + void setISO ( int iso ); + void setSharpness ( int sharpness ); + void setContrast ( int contrast ); + void setSaturation ( int saturation ); + void setEncoding ( RASPICAM_ENCODING encoding ); + void setExposure ( RASPICAM_EXPOSURE exposure ); + void setAWB ( RASPICAM_AWB awb ); + void setImageEffect ( RASPICAM_IMAGE_EFFECT imageEffect ); + void setMetering ( RASPICAM_METERING metering ); + void setHorizontalFlip ( bool hFlip ); + void setVerticalFlip ( bool vFlip ); + + unsigned int getWidth(); + unsigned int getHeight(); + unsigned int getBrightness(); + unsigned int getRotation(); + unsigned int getQuality(); + int getISO(); + int getSharpness(); + int getContrast(); + int getSaturation(); + RASPICAM_ENCODING getEncoding(); + RASPICAM_EXPOSURE getExposure(); + RASPICAM_AWB getAWB(); + RASPICAM_IMAGE_EFFECT getImageEffect(); + RASPICAM_METERING getMetering(); + bool isHorizontallyFlipped(); + bool isVerticallyFlipped(); + + }; +} +#endif + diff --git a/external_src/raspicam-0.1.3/src/raspicam_still_cv.cpp b/external_src/raspicam-0.1.3/src/raspicam_still_cv.cpp new file mode 100644 index 0000000..e3d8137 --- /dev/null +++ b/external_src/raspicam-0.1.3/src/raspicam_still_cv.cpp @@ -0,0 +1,185 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 "private_still/private_still_impl.h" +#include "raspicam_still_cv.h" +#include "scaler.h" +using namespace cv; +namespace raspicam { + RaspiCam_Still_Cv::RaspiCam_Still_Cv() { + _impl= new _private::Private_Impl_Still() ; + _isOpened=false; + image_buffer=0; + _impl->setEncoding ( raspicam::RASPICAM_ENCODING_RGB ); + _isGrabbed=false; + _impl->setVerticalFlip(true); + } + RaspiCam_Still_Cv::~RaspiCam_Still_Cv() { + release(); + delete _impl; + } + + + bool RaspiCam_Still_Cv::open ( ) { + _isOpened= _impl->initialize() ==0; + return _isOpened; + } + + bool RaspiCam_Still_Cv::isOpened ( ) const{ + return _isOpened; + } + bool RaspiCam_Still_Cv::grab () { + if ( image_buffer==0 ) image_buffer=new uchar [ _impl-> getImageBufferSize()]; + _isGrabbed= _impl->takePicture ( image_buffer, _impl-> getImageBufferSize() ); + return _isGrabbed; + } + void RaspiCam_Still_Cv::retrieve ( cv::Mat &image ) { + if ( image_buffer!=0 && _isGrabbed ) { + image.create ( _impl->getHeight(),_impl->getWidth(),CV_8UC3 ); + memcpy ( image.ptr ( 0 ),image_buffer,image.cols*image.rows*3 ); + } + } + + void RaspiCam_Still_Cv::release() {} + + + + + /**Returns the specified VideoCapture property + */ + + double RaspiCam_Still_Cv::get ( int propId ) { + + switch ( propId ) { + + case CV_CAP_PROP_FRAME_WIDTH : + return _impl->getWidth(); + case CV_CAP_PROP_FRAME_HEIGHT : + return _impl->getHeight(); + case CV_CAP_PROP_FPS: + return 30; + case CV_CAP_PROP_FORMAT : + return CV_8UC3; + case CV_CAP_PROP_MODE : + return 0; + case CV_CAP_PROP_BRIGHTNESS : + return _impl->getBrightness(); + case CV_CAP_PROP_CONTRAST : + return Scaler::scale ( -100,100,0,100, _impl->getContrast() ); + case CV_CAP_PROP_SATURATION : + return Scaler::scale ( -100,100,0,100, _impl->getSaturation() );; +// case CV_CAP_PROP_HUE : return _cam_impl->getSharpness(); + case CV_CAP_PROP_GAIN : + return Scaler::scale ( 0,800,0,100, _impl->getISO() ); + case CV_CAP_PROP_EXPOSURE : +// if ( _impl->getShutterSpeed() ==0 ) + return -1;//not yet +// else return Scaler::scale (0,330000, 0,100, _impl->getShutterSpeed() ) ; + break; + case CV_CAP_PROP_CONVERT_RGB : + return ( true ); +// case CV_CAP_PROP_WHITE_BALANCE :return _cam_impl->getAWB(); + default : + return -1; + }; + } + + /**Sets a property in the VideoCapture. + */ + + bool RaspiCam_Still_Cv::set ( int propId, double value ) { + + switch ( propId ) { + + case CV_CAP_PROP_FRAME_WIDTH : + if ( value!=_impl->getWidth() ) { + delete image_buffer; + image_buffer=0; + _impl->setWidth ( value ); + } + break; + case CV_CAP_PROP_FRAME_HEIGHT : + if ( value!=_impl->getHeight() ) { + delete image_buffer; + image_buffer=0; + _impl->setHeight ( value ); + } + break; + case CV_CAP_PROP_FORMAT : { + return false; //ONLY 8UC3 allowed at this moment + } + break; + case CV_CAP_PROP_MODE ://nothing to do yet + return false; + break; + case CV_CAP_PROP_BRIGHTNESS : + _impl->setBrightness ( value ); + break; + case CV_CAP_PROP_CONTRAST : + _impl->setContrast ( Scaler::scale ( 0,100,-100,100, value ) ); + break; + case CV_CAP_PROP_SATURATION : + _impl->setSaturation ( Scaler::scale ( 0,100,-100,100, value ) ); + break; +// case CV_CAP_PROP_HUE : return _cam_impl->getSharpness(); + case CV_CAP_PROP_GAIN : + _impl->setISO ( Scaler::scale ( 0,100,0,800, value ) ); + break; + case CV_CAP_PROP_EXPOSURE : +// if ( value>0 && value<=100 ) { +// _impl->setShutterSpeed ( Scaler::scale ( 0,100,0,330000, value ) ); +// } else { +// _impl->setExposure ( RASPICAM_EXPOSURE_AUTO ); +// _impl->setShutterSpeed ( 0 ); +// } + break; + case CV_CAP_PROP_CONVERT_RGB : +// CV_8UC3; + break; +// case CV_CAP_PROP_WHITE_BALANCE :return _cam_impl->getAWB(); + default : + return false; + }; + return true; + + } + std::string RaspiCam_Still_Cv::getId() const{ + return _impl->getId(); + } +} + + diff --git a/external_src/raspicam-0.1.3/src/raspicam_still_cv.h b/external_src/raspicam-0.1.3/src/raspicam_still_cv.h new file mode 100644 index 0000000..82fc56e --- /dev/null +++ b/external_src/raspicam-0.1.3/src/raspicam_still_cv.h @@ -0,0 +1,118 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 _RaspiCam_STILL_H +#define _RaspiCam_STILL_H +#include +#include "raspicamtypes.h" +#include +#include +namespace raspicam { + + namespace _private{ + class Private_Impl_Still; + }; + + + /**Raspicam API for still camera + */ + class RaspiCam_Still_Cv{ + //the implementation of the camera + _private::Private_Impl_Still *_impl; + + public: + /**Constructor + */ + RaspiCam_Still_Cv(); + /**Destructor + */ + ~RaspiCam_Still_Cv(); + /** Open capturing device for video capturing + */ + bool open ( void ); + /** + * Returns true if video capturing has been initialized already. + */ + bool isOpened() const; + /** + *Closes video file or capturing device. + */ + void release(); + + /** + * Grabs the next frame from video file or capturing device. + */ + bool grab(); + + /** + *Decodes and returns the grabbed video frame. + */ + void retrieve ( cv::Mat& image ); + + /**Returns the specified VideoCapture property + */ + + double get ( int propId ); + + /**Sets a property in the VideoCapture. + * + * + * Implemented properties: + * CV_CAP_PROP_FRAME_WIDTH,CV_CAP_PROP_FRAME_HEIGHT, + * CV_CAP_PROP_FORMAT: CV_8UC1 or CV_8UC3 + * CV_CAP_PROP_BRIGHTNESS: [0,100] + * CV_CAP_PROP_CONTRAST: [0,100] + * CV_CAP_PROP_SATURATION: [0,100] + * CV_CAP_PROP_GAIN: (iso): [0,100] + * CV_CAP_PROP_EXPOSURE: -1 auto. [1,100] shutter speed from 0 to 33ms + * + */ + + bool set ( int propId, double value ); + + /** Returns the camera identifier. We assume the camera id is the one of the raspberry obtained using raspberry serial number obtained in /proc/cpuinfo + */ + std::string getId() const; + + private: + uchar *image_buffer; + bool _isOpened; + bool _isGrabbed; + + }; +} +#endif + diff --git a/external_src/raspicam-0.1.3/src/raspicamtypes.h b/external_src/raspicam-0.1.3/src/raspicamtypes.h new file mode 100644 index 0000000..3d4479e --- /dev/null +++ b/external_src/raspicam-0.1.3/src/raspicamtypes.h @@ -0,0 +1,132 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 _RASPICAM_TYPES_H +#define _RASPICAM_TYPES_H + +namespace raspicam { + + /**Image formats + */ + enum RASPICAM_FORMAT{ + RASPICAM_FORMAT_YUV420, + RASPICAM_FORMAT_GRAY, + RASPICAM_FORMAT_BGR, + RASPICAM_FORMAT_RGB, + RASPICAM_FORMAT_IGNORE //do not use + }; + + /**Exposure types + */ + enum RASPICAM_EXPOSURE { + RASPICAM_EXPOSURE_OFF, + RASPICAM_EXPOSURE_AUTO, + RASPICAM_EXPOSURE_NIGHT, + RASPICAM_EXPOSURE_NIGHTPREVIEW, + RASPICAM_EXPOSURE_BACKLIGHT, + RASPICAM_EXPOSURE_SPOTLIGHT, + RASPICAM_EXPOSURE_SPORTS, + RASPICAM_EXPOSURE_SNOW, + RASPICAM_EXPOSURE_BEACH, + RASPICAM_EXPOSURE_VERYLONG, + RASPICAM_EXPOSURE_FIXEDFPS, + RASPICAM_EXPOSURE_ANTISHAKE, + RASPICAM_EXPOSURE_FIREWORKS + } ; + + /**Auto white balance types + */ + enum RASPICAM_AWB { + RASPICAM_AWB_OFF, + RASPICAM_AWB_AUTO, + RASPICAM_AWB_SUNLIGHT, + RASPICAM_AWB_CLOUDY, + RASPICAM_AWB_SHADE, + RASPICAM_AWB_TUNGSTEN, + RASPICAM_AWB_FLUORESCENT, + RASPICAM_AWB_INCANDESCENT, + RASPICAM_AWB_FLASH, + RASPICAM_AWB_HORIZON + } ; + + /**Image effects + */ + enum RASPICAM_IMAGE_EFFECT { + RASPICAM_IMAGE_EFFECT_NONE, + RASPICAM_IMAGE_EFFECT_NEGATIVE, + RASPICAM_IMAGE_EFFECT_SOLARIZE, + RASPICAM_IMAGE_EFFECT_SKETCH, + RASPICAM_IMAGE_EFFECT_DENOISE, + RASPICAM_IMAGE_EFFECT_EMBOSS, + RASPICAM_IMAGE_EFFECT_OILPAINT, + RASPICAM_IMAGE_EFFECT_HATCH, + RASPICAM_IMAGE_EFFECT_GPEN, + RASPICAM_IMAGE_EFFECT_PASTEL, + RASPICAM_IMAGE_EFFECT_WATERCOLOR, + RASPICAM_IMAGE_EFFECT_FILM, + RASPICAM_IMAGE_EFFECT_BLUR, + RASPICAM_IMAGE_EFFECT_SATURATION, + RASPICAM_IMAGE_EFFECT_COLORSWAP, + RASPICAM_IMAGE_EFFECT_WASHEDOUT, + RASPICAM_IMAGE_EFFECT_POSTERISE, + RASPICAM_IMAGE_EFFECT_COLORPOINT, + RASPICAM_IMAGE_EFFECT_COLORBALANCE, + RASPICAM_IMAGE_EFFECT_CARTOON + } ; + + /**Metering types + */ + enum RASPICAM_METERING { + RASPICAM_METERING_AVERAGE, + RASPICAM_METERING_SPOT, + RASPICAM_METERING_BACKLIT, + RASPICAM_METERING_MATRIX + } ; + /*Econdig modes (for still mode) + */ + + typedef enum RASPICAM_ENCODING { + RASPICAM_ENCODING_JPEG, + RASPICAM_ENCODING_BMP, + RASPICAM_ENCODING_GIF, + RASPICAM_ENCODING_PNG, + RASPICAM_ENCODING_RGB + } RASPICAM_ENCODING; + +}; +#endif + diff --git a/external_src/raspicam-0.1.3/src/scaler.h b/external_src/raspicam-0.1.3/src/scaler.h new file mode 100644 index 0000000..4c277c6 --- /dev/null +++ b/external_src/raspicam-0.1.3/src/scaler.h @@ -0,0 +1,47 @@ +#ifndef _RASPICAM_SCALER_H_ +#define _RASPICAM_SCALER_H_ +namespace raspicam { + + /**CLass to calculate linear scale + */ + class Scaler + { + float a,b; + float _inMin, _inMax, _outMin,_outMax; + public: + float aa; + float bb; + Scaler() {} + Scaler ( float inMin, float inMax, float outMin,float outMax ) { + setParams ( inMin,inMax,outMin,outMax ); + } + + + void setParams ( float inMin, float inMax, float outMin,float outMax ) { + _inMin=inMin; + _inMax=inMax; + _outMin=outMin; + _outMax=outMax; + double aux = ( _inMax - _inMin ); + if ( aux != 0.0 ) { + a = ( _outMax - _outMin ) /aux; + b = _outMax - ( a * _inMax ); + } else + a = b = 0.0; + aa = ( _outMax - _outMin ) / ( _inMax - _inMin ); + bb= ( _outMax - ( aa * _inMax ) ); + } + inline float operator() ( float val ) const + { + if ( val<=_inMin ) return _outMin; + else if ( val>=_inMax ) return _outMax; + return val * aa + bb; + } + + static float scale ( float inMin, float inMax, float outMin,float outMax,float val ) { + Scaler s ( inMin,inMax,outMin,outMax ); + return s ( val ); + } + }; +} +#endif diff --git a/external_src/raspicam-0.1.3/utils/CMakeLists.txt b/external_src/raspicam-0.1.3/utils/CMakeLists.txt new file mode 100644 index 0000000..7580c43 --- /dev/null +++ b/external_src/raspicam-0.1.3/utils/CMakeLists.txt @@ -0,0 +1,18 @@ +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src) +LINK_LIBRARIES(${PROJECT_NAME} ) + + +ADD_EXECUTABLE(raspicam_test raspicam_test.cpp ) +INSTALL(TARGETS raspicam_test RUNTIME DESTINATION bin) + +ADD_EXECUTABLE(raspicam_still_test raspicam_still_test.cpp ) +INSTALL(TARGETS raspicam_still_test RUNTIME DESTINATION bin) + +IF (OpenCV_FOUND) +ADD_EXECUTABLE(raspicam_cv_test raspicam_cv_test.cpp ) +target_link_libraries(raspicam_cv_test ${PROJECT_NAME}_cv) +ADD_EXECUTABLE(raspicam_cv_still_test raspicam_cv_still_test.cpp ) +target_link_libraries(raspicam_cv_still_test ${PROJECT_NAME}_cv) +INSTALL(TARGETS raspicam_cv_test raspicam_cv_still_test RUNTIME DESTINATION bin) + +ENDIF() diff --git a/external_src/raspicam-0.1.3/utils/raspicam_cv_still_test.cpp b/external_src/raspicam-0.1.3/utils/raspicam_cv_still_test.cpp new file mode 100644 index 0000000..aaa2ddb --- /dev/null +++ b/external_src/raspicam-0.1.3/utils/raspicam_cv_still_test.cpp @@ -0,0 +1,82 @@ +/********************************************************** + Software developed by AVA ( Ava Group of the University of Cordoba, ava at uco dot es) + Main author Rafael Munoz Salinas (rmsalinas at uco dot es) + This software is released under BSD license as expressed below +------------------------------------------------------------------- +Copyright (c) 2013, AVA ( Ava Group University of Cordoba, ava at uco dot es) +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed by the Ava group of the University of Cordoba. + +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AVA ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AVA BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 +#include +#include +#include "raspicam_still_cv.h" +using namespace std; + +raspicam::RaspiCam_Still_Cv Camera; +//Returns the value of a param. If not present, returns the defvalue +float getParamVal ( string id,int argc,char **argv,float defvalue ) { + for ( int i=0; i +#include +#include +#include +#include +#include "raspicam_cv.h" + +using namespace std; +bool doTestSpeedOnly=false; +//parse command line +//returns the index of a command line param in argv. If not found, return -1 +int findParam ( string param,int argc,char **argv ) { + int idx=-1; + for ( int i=0; i +#include +#include +#include +#include +#include +#include "raspicam.h" +using namespace std; +bool doTestSpeedOnly=false; +size_t nFramesCaptured=100; +//parse command line +//returns the index of a command line param in argv. If not found, return -1 + +int findParam ( string param,int argc,char **argv ) { + int idx=-1; + for ( int i=0; i +#include +class Timer{ + private: + struct timeval _start, _end; + +public: + Timer(){} + void start(){ + gettimeofday(&_start, NULL); + } + void end(){ + gettimeofday(&_end, NULL); + } + double getSecs(){ + return double(((_end.tv_sec - _start.tv_sec) * 1000 + (_end.tv_usec - _start.tv_usec)/1000.0) + 0.5)/1000.; + } + +}; + +void saveImage ( string filepath,unsigned char *data,raspicam::RaspiCam &Camera ) { + std::ofstream outFile ( filepath.c_str(),std::ios::binary ); + if ( Camera.getFormat()==raspicam::RASPICAM_FORMAT_BGR || Camera.getFormat()==raspicam::RASPICAM_FORMAT_RGB ) { + outFile<<"P6\n"; + } else if ( Camera.getFormat()==raspicam::RASPICAM_FORMAT_GRAY ) { + outFile<<"P5\n"; + } else if ( Camera.getFormat()==raspicam::RASPICAM_FORMAT_YUV420 ) { //made up format + outFile<<"P7\n"; + } + outFile<0 ) { //save image if not in inifite loop + std::stringstream fn; + fn<<"image"; + if (i<10) fn<<"0"; + fn<