@@ -6,10 +6,18 @@ enable_testing() | |||
find_package( OpenCV REQUIRED ) | |||
include_directories( ${OpenCV_INCLUDE_DIRS} ) | |||
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/Input ) | |||
link_directories( ${Input_SOURCE_DIRS} ) | |||
add_subdirectory(Input) | |||
target_include_directories(Input PRIVATE .) | |||
add_executable(lfr_image_processing lfr.cpp) | |||
target_link_libraries( lfr_image_processing ${OpenCV_LIBS} ) | |||
target_link_libraries( lfr_image_processing ${OpenCV_LIBS}) | |||
target_link_libraries( lfr_image_processing Input ) | |||
set(CPACK_PROJECT_NAME ${PROJECT_NAME}) | |||
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) |
@@ -1,8 +0,0 @@ | |||
#include <iostream> | |||
#include <opencv2/opencv.hpp> | |||
int main(void) | |||
{ | |||
std::cout<<"Hello world"; | |||
//Kommentar von Baran | |||
} |
@@ -0,0 +1,12 @@ | |||
find_package( OpenCV REQUIRED ) | |||
include_directories( ${OpenCV_INCLUDE_DIRS} ) | |||
add_library(Input input.cpp) | |||
set_target_properties(Input PROPERTIES VERSION ${PROJECT_VERSION}) | |||
target_include_directories(Input PRIVATE .) | |||
target_link_libraries( Input ${OpenCV_LIBS}) | |||
set(CPACK_PROJECT_NAME ${PROJECT_NAME}) | |||
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) | |||
include(CPack) |
@@ -0,0 +1,254 @@ | |||
# ---------------------------------------------------------------------------- | |||
# Basic Configuration | |||
# ---------------------------------------------------------------------------- | |||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8) | |||
if (POLICY CMP0048) | |||
cmake_policy(SET CMP0048 NEW) | |||
endif (POLICY CMP0048) | |||
PROJECT(raspicam) | |||
set(PROJECT_VERSION "0.1.2") | |||
string(REGEX MATCHALL "[0-9]" PROJECT_VERSION_PARTS "${PROJECT_VERSION}") | |||
list(GET PROJECT_VERSION_PARTS 0 PROJECT_VERSION_MAJOR) | |||
list(GET PROJECT_VERSION_PARTS 1 PROJECT_VERSION_MINOR) | |||
list(GET PROJECT_VERSION_PARTS 2 PROJECT_VERSION_PATCH) | |||
set(PROJECT_SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}") | |||
#------------------------------------------------------ | |||
# Build type | |||
#------------------------------------------------------ | |||
IF(NOT CMAKE_BUILD_TYPE ) | |||
SET( CMAKE_BUILD_TYPE "Release" ) | |||
ENDIF() | |||
#------------------------------------------------------ | |||
# Lib Names and Dirs | |||
#------------------------------------------------------ | |||
# Postfix of so's: | |||
set(PROJECT_DLLVERSION) | |||
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_INSTALL_PREFIX}/lib/cmake/ /usr/lib/cmake) | |||
OPTION(BUILD_SHARED_LIBS "Set to OFF to build static libraries" ON) | |||
OPTION(BUILD_UTILS "Acitvates/Deactivates building utils libraries" ON) | |||
# ---------------------------------------------------------------------------- | |||
# Find Dependencies | |||
# ---------------------------------------------------------------------------- | |||
#Add include to dependencies dir | |||
include_directories(${PROJECT_SOURCE_DIR}/dependencies ${PROJECT_SOURCE_DIR}/dependencies/mmal ${PROJECT_SOURCE_DIR}/dependencies/vcos) | |||
#find the mmal libraries(I use conditional because I normally comile in pc) | |||
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES arm*) | |||
FIND_LIBRARY(mmalcore_LIBS NAMES mmal_core PATHS /opt/vc/lib) | |||
FIND_LIBRARY(mmalutil_LIBS NAMES mmal_util PATHS /opt/vc/lib) | |||
FIND_LIBRARY(mmal_LIBS NAMES mmal PATHS /opt/vc/lib) | |||
IF( (NOT mmal_LIBS ) OR (NOT mmalutil_LIBS) OR (NOT mmalcore_LIBS) ) | |||
MESSAGE(FATAL_ERROR "Could not find mmal libraries") | |||
ENDIF() | |||
set(REQUIRED_LIBRARIES ${REQUIRED_LIBRARIES} ${mmalcore_LIBS} ${mmalutil_LIBS} ${mmal_LIBS} ) | |||
ENDIF() | |||
#If opencv installed, creates the libraspicam_cv library module | |||
FIND_PACKAGE(OpenCV) | |||
IF(OpenCV_FOUND) | |||
include_directories(${OpenCV_INCLUDE_DIRS}) | |||
SET(LIB_COMPONENTS ${LIB_COMPONENTS} ${PROJECT_NAME}_cv) | |||
SET(PROJECT_CV_CREATED_FLAG "YES") | |||
ENDIF() | |||
# ---------------------------------------------------------------------------- | |||
# PROJECT CONFIGURATION | |||
# force some variables that could be defined in the command line to be written to cache | |||
# ---------------------------------------------------------------------------- | |||
OPTION(INSTALL_DOC "Set to ON to build/install Documentation" OFF) | |||
IF (INSTALL_DOC) | |||
FIND_PACKAGE(Doxygen REQUIRED) | |||
MESSAGE( STATUS "INSTALL_DOC: ${INSTALL_DOC} ") | |||
INCLUDE("${PROJECT_SOURCE_DIR}/generateDoc.cmake") | |||
GENERATE_DOCUMENTATION(${PROJECT_SOURCE_DIR}/dox.in) | |||
ENDIF() | |||
# ---------------------------------------------------------------------------- | |||
# Uninstall target, for "make uninstall" | |||
# ---------------------------------------------------------------------------- | |||
CONFIGURE_FILE( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) | |||
ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") | |||
# ---------------------------------------------------------------------------- | |||
# create configuration file from .in file (If you use windows take care with paths) | |||
# ---------------------------------------------------------------------------- | |||
CONFIGURE_FILE("${PROJECT_SOURCE_DIR}/config.cmake.in" "${PROJECT_BINARY_DIR}/Find${PROJECT_NAME}.cmake") | |||
CONFIGURE_FILE("${PROJECT_SOURCE_DIR}/config.cmake.in" "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake") | |||
INSTALL(FILES "${PROJECT_BINARY_DIR}/Find${PROJECT_NAME}.cmake" DESTINATION lib/cmake/ ) | |||
INSTALL(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" DESTINATION lib/cmake/ ) | |||
# ---------------------------------------------------------------------------- | |||
# Program Optimization and debug (Extracted from OpenCV) | |||
# ---------------------------------------------------------------------------- | |||
set(WARNINGS_ARE_ERRORS OFF CACHE BOOL "Treat warnings as errors") | |||
set(WHOLE_PROGRAM_OPTIMIZATION OFF CACHE BOOL "Flags for whole program optimization.") | |||
set(EXTRA_C_FLAGS "") | |||
set(EXTRA_C_FLAGS_RELEASE "") | |||
set(EXTRA_C_FLAGS_DEBUG "") | |||
set(EXTRA_EXE_LINKER_FLAGS "") | |||
set(EXTRA_EXE_LINKER_FLAGS_RELEASE "") | |||
set(EXTRA_EXE_LINKER_FLAGS_DEBUG "") | |||
IF(CMAKE_COMPILER_IS_GNUCXX OR MINGW) | |||
set(ENABLE_PROFILING OFF CACHE BOOL "Enable profiling in the GCC compiler (Add flags: -g -pg)") | |||
set(USE_OMIT_FRAME_POINTER ON CACHE BOOL "Enable -fomit-frame-pointer for GCC") | |||
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES arm*) # We can use only -O2 because the -O3 causes gcc crash | |||
set(USE_O2 ON CACHE BOOL "Enable -O2 for GCC") | |||
set(USE_FAST_MATH ON CACHE BOOL "Enable -ffast-math for GCC") | |||
endif() | |||
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES powerpc*) | |||
set(USE_O3 ON CACHE BOOL "Enable -O3 for GCC") | |||
set(USE_POWERPC ON CACHE BOOL "Enable PowerPC for GCC") | |||
endif () | |||
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES amd64* OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES x86_64*) | |||
set(USE_O3 ON CACHE BOOL "Enable -O3 for GCC") | |||
set(USE_FAST_MATH ON CACHE BOOL "Enable -ffast-math for GCC") | |||
set(USE_MMX ON CACHE BOOL "Enable MMX for GCC") | |||
set(USE_SSE ON CACHE BOOL "Enable SSE for GCC") | |||
set(USE_SSE2 ON CACHE BOOL "Enable SSE2 for GCC") | |||
set(USE_SSE3 ON CACHE BOOL "Enable SSE3 for GCC") | |||
endif() | |||
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES i686* OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES x86) | |||
set(USE_O3 ON CACHE BOOL "Enable -O3 for GCC") | |||
set(USE_FAST_MATH ON CACHE BOOL "Enable -ffast-math for GCC") | |||
set(USE_MMX ON CACHE BOOL "Enable MMX for GCC") | |||
set(USE_SSE OFF CACHE BOOL "Enable SSE for GCC") | |||
set(USE_SSE2 OFF CACHE BOOL "Enable SSE2 for GCC") | |||
set(USE_SSE3 OFF CACHE BOOL "Enable SSE3 for GCC") | |||
endif () | |||
set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} -Wall") | |||
if(WARNINGS_ARE_ERRORS) | |||
set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} -Werror") | |||
endif() | |||
# The -Wno-long-long is required in 64bit systems when including sytem headers. | |||
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES x86_64* OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES amd64*) | |||
set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} -Wno-long-long") | |||
endif() | |||
# Whole program optimization | |||
if(WHOLE_PROGRAM_OPTIMIZATION) | |||
set(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -fwhole-program --combine") | |||
endif() | |||
# Other optimizations | |||
if(USE_OMIT_FRAME_POINTER) | |||
set(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -fomit-frame-pointer") | |||
endif() | |||
if(USE_O2) | |||
set(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -O2") | |||
endif() | |||
if(USE_O3) | |||
set(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -O3") | |||
endif() | |||
if(USE_FAST_MATH) | |||
set(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -ffast-math") | |||
endif() | |||
if(USE_POWERPC) | |||
set(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -mcpu=G3 -mtune=G5") | |||
endif() | |||
if(USE_MMX) | |||
set(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -mmmx") | |||
endif() | |||
if(USE_SSE) | |||
set(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -msse") | |||
endif() | |||
if(USE_SSE2) | |||
set(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -msse2") | |||
endif() | |||
if(USE_SSE3 AND NOT MINGW) # SSE3 should be disabled under MingW because it generates compiler errors | |||
set(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -msse3") | |||
endif() | |||
if(ENABLE_PROFILING) | |||
set(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -pg -g") | |||
else() | |||
if(NOT APPLE) | |||
set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} -ffunction-sections") | |||
endif() | |||
endif() | |||
# Parallel mode | |||
if(ENABLE_OPENMP) | |||
set(EXTRA_C_FLAGS "${EXTRA_C_FLAGS} -fopenmp") | |||
set(LINKER_LIBS ${LINKER_LIBS} gomp) | |||
endif() | |||
set(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -DNDEBUG") | |||
set(EXTRA_C_FLAGS_DEBUG "-g3 -O0 -DDEBUG -D_DEBUG -W -Wextra -Wno-return-type") | |||
MESSAGE( STATUS "-------------------------------------------------------------------------------" ) | |||
message( STATUS "GNU COMPILER") | |||
MESSAGE( STATUS "-------------------------------------------------------------------------------" ) | |||
ENDIF () | |||
IF(${CMAKE_SYSTEM_PROCESSOR} MATCHES armv6l ) ##BEAGLE BOARD | |||
SET(EXTRA_C_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -ftree-vectorize") | |||
ENDIF() | |||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-pedantic -Wall -Wno-variadic-macros -std=c++0x -Wl,--no-as-needed")#for using condition variables | |||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_C_FLAGS} ") | |||
SET(CMAKE_CXX_FLAGS_RELEASE "${EXTRA_C_FLAGS_RELEASE} -lpthread") | |||
SET(CMAKE_CXX_FLAGS_DEBUG "${EXTRA_C_FLAGS_DEBUG} -lpthread") | |||
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${EXTRA_EXE_LINKER_FLAGS}") | |||
SET(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${EXTRA_EXE_LINKER_FLAGS_RELEASE}") | |||
SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${EXTRA_EXE_LINKER_FLAGS_DEBUG}") | |||
#------------------------------------------------ | |||
# DIRS | |||
#------------------------------------------------ | |||
ADD_SUBDIRECTORY(src) | |||
IF(BUILD_UTILS) | |||
ADD_SUBDIRECTORY(utils) | |||
ENDIF() | |||
# ---------------------------------------------------------------------------- | |||
# display status message for important variables | |||
# ---------------------------------------------------------------------------- | |||
message( STATUS ) | |||
MESSAGE( STATUS "-------------------------------------------------------------------------------" ) | |||
message( STATUS "General configuration for ${PROJECT_NAME} ${PROJECT_VERSION}") | |||
MESSAGE( STATUS "-------------------------------------------------------------------------------" ) | |||
message( STATUS ) | |||
message(" Built as dynamic libs?:" ${BUILD_SHARED_LIBS}) | |||
message(" Compiler:" "${CMAKE_COMPILER}" "${CMAKE_CXX_COMPILER}") | |||
message( STATUS "C++ flags (Release): ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE}") | |||
message( STATUS "C++ flags (Debug): ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_DEBUG}") | |||
message( STATUS "CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}") | |||
message( STATUS "CMAKE_BINARY_DIR: ${CMAKE_BINARY_DIR}") | |||
MESSAGE( STATUS ) | |||
MESSAGE( STATUS "CMAKE_SYSTEM_PROCESSOR = ${CMAKE_SYSTEM_PROCESSOR}" ) | |||
MESSAGE( STATUS "BUILD_SHARED_LIBS = ${BUILD_SHARED_LIBS}" ) | |||
MESSAGE( STATUS "BUILD_UTILS = ${BUILD_UTILS}" ) | |||
MESSAGE( STATUS "CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX}" ) | |||
MESSAGE( STATUS "CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}" ) | |||
MESSAGE( STATUS "CMAKE_MODULE_PATH = ${CMAKE_MODULE_PATH}" ) | |||
MESSAGE( STATUS ) | |||
MESSAGE( STATUS "CREATE OPENCV MODULE=${OpenCV_FOUND}") | |||
MESSAGE( STATUS "CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}") | |||
MESSAGE( STATUS "REQUIRED_LIBRARIES=${REQUIRED_LIBRARIES}") | |||
MESSAGE( STATUS ) | |||
MESSAGE( STATUS ) | |||
MESSAGE( STATUS "Change a value with: cmake -D<Variable>=<Value>" ) | |||
MESSAGE( STATUS ) |
@@ -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 |
@@ -0,0 +1,210 @@ | |||
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<Variable>=<Value> | |||
-- | |||
-- 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 <ctime> | |||
#include <unistd.h> | |||
#include <fstream> | |||
#include <iostream> | |||
#include <raspicam/raspicam.h> | |||
using namespace std; | |||
int main ( int argc,char **argv ) { | |||
raspicam::RaspiCam Camera; //Cmaera object | |||
//Open camera | |||
cout<<"Opening Camera..."<<endl; | |||
if ( !Camera.open()) {cerr<<"Error opening camera"<<endl;return -1;} | |||
//wait a while until camera stabilizes | |||
cout<<"Sleeping for 3 secs"<<endl; | |||
sleep(3); | |||
//capture | |||
Camera.grab(); | |||
//allocate memory | |||
unsigned char *data=new unsigned char[ Camera.getImageTypeSize ( raspicam::RASPICAM_FORMAT_RGB )]; | |||
//extract the image in rgb format | |||
Camera.retrieve ( data,raspicam::RASPICAM_FORMAT_RGB );//get camera image | |||
//save | |||
std::ofstream outFile ( "raspicam_image.ppm",std::ios::binary ); | |||
outFile<<"P6\n"<<Camera.getWidth() <<" "<<Camera.getHeight() <<" 255\n"; | |||
outFile.write ( ( char* ) data, Camera.getImageTypeSize ( raspicam::RASPICAM_FORMAT_RGB ) ); | |||
cout<<"Image saved at raspicam_image.ppm"<<endl; | |||
//free resrources | |||
delete data; | |||
return 0; | |||
} | |||
// | |||
Now, create a file named CMakeLists.txt and add: | |||
##################################### | |||
cmake_minimum_required (VERSION 2.8) | |||
project (raspicam_test) | |||
set (CMAKE_MODULE_PATH "/usr/local/lib/cmake/${CMAKE_MODULE_PATH}") | |||
find_package(raspicam REQUIRED) | |||
add_executable (simpletest_raspicam simpletest_raspicam.cpp) | |||
target_link_libraries (simpletest_raspicam ${raspicam_LIBS}) | |||
##################################### | |||
Finally, create,compile and execute | |||
mkdir build | |||
cd build | |||
cmake .. | |||
make | |||
./simpletest_raspicam | |||
A more complete sample project is provided in SourceForge. | |||
* OpenCV Interface | |||
If the OpenCV is found when compiling the library, the libraspicam_cv.so module is created and the RaspiCam_Cv class available. | |||
Take a look at the examples in utils to see how to use the class. In addition, we show here how you can use the RaspiCam_Cv in your own project using cmake. | |||
First create a file with the name simpletest_raspicam_cv.cpp and add the following code | |||
#include <ctime> | |||
#include <iostream> | |||
#include <raspicam/raspicam_cv.h> | |||
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..."<<endl; | |||
if (!Camera.open()) {cerr<<"Error opening the camera"<<endl;return -1;} | |||
//Start capture | |||
cout<<"Capturing "<<nCount<<" frames ...."<<endl; | |||
time ( &timer_begin ); | |||
for ( int i=0; i<nCount; i++ ) { | |||
Camera.grab(); | |||
Camera.retrieve ( image); | |||
if ( i%5==0 ) cout<<"\r captured "<<i<<" images"<<std::flush; | |||
} | |||
cout<<"Stop camera..."<<endl; | |||
Camera.release(); | |||
//show time statistics | |||
time ( &timer_end ); /* get current time; same as: timer = time(NULL) */ | |||
double secondsElapsed = difftime ( timer_end,timer_begin ); | |||
cout<< secondsElapsed<<" seconds for "<< nCount<<" frames : FPS = "<< ( float ) ( ( float ) ( nCount ) /secondsElapsed ) <<endl; | |||
//save image | |||
cv::imwrite("raspicam_cv_image.jpg",image); | |||
cout<<"Image saved at raspicam_cv_image.jpg"<<endl; | |||
} | |||
Now, create a file named CMakeLists.txt and add: | |||
##################################### | |||
cmake_minimum_required (VERSION 2.8) | |||
project (raspicam_test) | |||
set (CMAKE_MODULE_PATH "/usr/local/lib/cmake/${CMAKE_MODULE_PATH}") | |||
find_package(raspicam REQUIRED) | |||
find_package(OpenCV) | |||
IF ( OpenCV_FOUND AND raspicam_CV_FOUND) | |||
MESSAGE(STATUS "COMPILING OPENCV TESTS") | |||
add_executable (simpletest_raspicam_cv simpletest_raspicam_cv.cpp) | |||
target_link_libraries (simpletest_raspicam_cv ${raspicam_CV_LIBS}) | |||
ELSE() | |||
MESSAGE(FATAL_ERROR "OPENCV NOT FOUND IN YOUR SYSTEM") | |||
ENDIF() | |||
##################################### | |||
Finally, create,compile and execute | |||
mkdir build | |||
cd build | |||
cmake .. | |||
make | |||
./simpletest_raspicam_cv | |||
@@ -0,0 +1,208 @@ | |||
# RaspiCam: C++ API for using Raspberry camera (with OpenCV) | |||
This library allows to use the Raspberry Pi Camera under BSD License. | |||
The project is started by the AVA research group (rafael Muñoz Salinas; rmsalinas@uco.es) and is now maintained | |||
on this GIT repository by Cédric Verstraeten. Please note that is NOT the OFFICIAL repository of RaspiCam, these can be found [here](http://www.uco.es/investiga/grupos/ava/node/40). | |||
This repository is used in the [Kerberos.io](https://github.com/kerberos-io) project. | |||
## Release notes | |||
Update 2014/03/04: version 0.1.1 released Download at SourceForge | |||
Main feaure in 0.0.7 : Still camera API. You can now use the still mode for high resolution (includes OpenCv interface). See examples for more info. | |||
Notes: | |||
Requires to update the firmware to use shutterspeed (sudo rpi-update) | |||
Main features | |||
- Provides class RaspiCam for easy and full control of the camera | |||
- Provides class RaspiCam_Still and RaspiCam_Still_Cv for controlling the camera in still mode | |||
- 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 | |||
- Provides class RaspiCam_Still and RaspiCam_Still_Cv for using the still camera mode | |||
- Easy compilation/installation using cmake. | |||
- No need to install development file of userland. Implementation is hidden. | |||
- Many examples | |||
Performance | |||
Following, we show the capture performance of the library (measured capturing 600 frames). | |||
Gray and YUV420 Mode | |||
- 1280x960: 29.5fps, 640x480 : 29.5fps, 320x240 : 29.5fps | |||
RGB Mode | |||
- 1280x960: 28 fps, 640x480 : 29.29fps, 320x240 : 29.24fps | |||
BGR Mode | |||
- 1280x960: 14 fps, 640x480 : 29.29fps, 320x240 : 29.24fps | |||
Note: when using the full resolution video callbacks with the full resolution of the Raspberry Pi Camera v2, you will likely get an error such as `mmal: mmal_vc_port_enable: failed to enable port vc.ril.camera:out:1(BGR3): ENOSPC`. In order to fix this increase your GPU memory to at least 256MB. | |||
Color conversion is the most time consuming part. We still need to improve that part. Go to src/private and check if you can contribute! | |||
Note: the library is compiled with the options: -Wall -ffunction-sections -fomit-frame-pointer -O2 -ffast-math -DNDEBUG -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -ftree-vectorize | |||
Note 2: the library is currently setting the camera in video mode. So, maximum resolution is 1280x960. I am working on the still port to enable higher resolutions. | |||
## Compiling | |||
Clone the repository to your raspberry. Then, uncompress the file and compile | |||
git clone https://github.com/cedricve/raspicam.git | |||
cd raspicam | |||
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<Variable>=<Value> | |||
-- | |||
-- 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 following output; otherwise this option will be 0 and the opencv module of the library will not be compiled. | |||
-- CREATE OPENCV MODULE=1 | |||
Finally compile, install and update the ldconfig: | |||
make | |||
sudo make install | |||
sudo ldconfig | |||
After that, you have the programs raspicam_test and raspicam_cv_test (if opencv was enabled) in build/utils. | |||
Run the first program to check that compilation is ok. | |||
``` | |||
sudo ./raspicam_test | |||
sudo ./raspicam_cv_test | |||
``` | |||
### Using it in your projects | |||
You can learn how to use the library by taking a look at the examples in the utils directory and by analyzing the header files. In addition, we provide a some simple examples on how to use the library with cmake. | |||
First, create a directory for our own project. Then, go in and create a file with the name simpletest_raspicam.cpp and add the following code | |||
/** | |||
*/ | |||
#include <ctime> | |||
#include <fstream> | |||
#include <iostream> | |||
#include <raspicam/raspicam.h> | |||
using namespace std; | |||
int main ( int argc,char **argv ) { | |||
raspicam::RaspiCam Camera; //Camera object | |||
//Open camera | |||
cout<<"Opening Camera..."<<endl; | |||
if ( !Camera.open()) {cerr<<"Error opening camera"<<endl;return -1;} | |||
//wait a while until camera stabilizes | |||
cout<<"Sleeping for 3 secs"<<endl; | |||
sleep(3); | |||
//capture | |||
Camera.grab(); | |||
//allocate memory | |||
unsigned char *data=new unsigned char[ Camera.getImageTypeSize ( raspicam::RASPICAM_FORMAT_RGB )]; | |||
//extract the image in rgb format | |||
Camera.retrieve ( data,raspicam::RASPICAM_FORMAT_RGB );//get camera image | |||
//save | |||
std::ofstream outFile ( "raspicam_image.ppm",std::ios::binary ); | |||
outFile<<"P6\n"<<Camera.getWidth() <<" "<<Camera.getHeight() <<" 255\n"; | |||
outFile.write ( ( char* ) data, Camera.getImageTypeSize ( raspicam::RASPICAM_FORMAT_RGB ) ); | |||
cout<<"Image saved at raspicam_image.ppm"<<endl; | |||
//free resrources | |||
delete data; | |||
return 0; | |||
} | |||
For cmake users, create a file named CMakeLists.txt and add: | |||
cmake_minimum_required (VERSION 2.8) | |||
project (raspicam_test) | |||
find_package(raspicam REQUIRED) | |||
add_executable (simpletest_raspicam simpletest_raspicam.cpp) | |||
target_link_libraries (simpletest_raspicam ${raspicam_LIBS}) | |||
Finally, create build dir,compile and execute | |||
mkdir build | |||
cd build | |||
cmake .. | |||
make | |||
./simpletest_raspicam | |||
If you do not like cmake, simply | |||
g++ simpletest_raspicam.cpp -o simpletest_raspicam -I/usr/local/include -lraspicam -lmmal -lmmal_core -lmmal_util | |||
### OpenCV Interface | |||
If the OpenCV is found when compiling the library, the libraspicam_cv.so module is created and the RaspiCam_Cv class available. Take a look at the examples in utils to see how to use the class. In addition, we show here how you can use the RaspiCam_Cv in your own project using cmake. | |||
First create a file with the name simpletest_raspicam_cv.cpp and add the following code | |||
#include <ctime> | |||
#include <iostream> | |||
#include <raspicam/raspicam_cv.h> | |||
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..."<<endl; | |||
if (!Camera.open()) {cerr<<"Error opening the camera"<<endl;return -1;} | |||
//Start capture | |||
cout<<"Capturing "<<nCount<<" frames ...."<<endl; | |||
time ( &timer_begin ); | |||
for ( int i=0; i<nCount; i++ ) { | |||
Camera.grab(); | |||
Camera.retrieve ( image); | |||
if ( i%5==0 ) cout<<"\r captured "<<i<<" images"<<std::flush; | |||
} | |||
cout<<"Stop camera..."<<endl; | |||
Camera.release(); | |||
//show time statistics | |||
time ( &timer_end ); /* get current time; same as: timer = time(NULL) */ | |||
double secondsElapsed = difftime ( timer_end,timer_begin ); | |||
cout<< secondsElapsed<<" seconds for "<< nCount<<" frames : FPS = "<< ( float ) ( ( float ) ( nCount ) /secondsElapsed ) <<endl; | |||
//save image | |||
cv::imwrite("raspicam_cv_image.jpg",image); | |||
cout<<"Image saved at raspicam_cv_image.jpg"<<endl; | |||
} | |||
For cmake users, create a file named CMakeLists.txt and add: | |||
cmake_minimum_required (VERSION 2.8) | |||
project (raspicam_test) | |||
find_package(raspicam REQUIRED) | |||
find_package(OpenCV) | |||
IF ( OpenCV_FOUND AND raspicam_CV_FOUND) | |||
MESSAGE(STATUS "COMPILING OPENCV TESTS") | |||
add_executable (simpletest_raspicam_cv simpletest_raspicam_cv.cpp) | |||
target_link_libraries (simpletest_raspicam_cv ${raspicam_CV_LIBS}) | |||
ELSE() | |||
MESSAGE(FATAL_ERROR "OPENCV NOT FOUND IN YOUR SYSTEM") | |||
ENDIF() | |||
Finally, create,compile and execute | |||
mkdir build | |||
cd build | |||
cmake .. | |||
make | |||
./simpletest_raspicam_cv | |||
If you do not like cmake: | |||
g++ simpletest_raspicam_cv.cpp -o simpletest_raspicam_cv -I/usr/local/include/ -lraspicam -lraspicam_cv -lmmal -lmmal_core -lmmal_util -lopencv_core -lopencv_highgui | |||
@@ -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) | |||
@@ -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@) |
@@ -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) |
@@ -0,0 +1 @@ | |||
add_subdirectory(brcmjpeg) |
@@ -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) |
@@ -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; | |||
} |
@@ -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 */ |
@@ -0,0 +1,236 @@ | |||
/* | |||
Copyright (c) 2012, Broadcom Europe Ltd | |||
All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright | |||
notice, this list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright | |||
notice, this list of conditions and the following disclaimer in the | |||
documentation and/or other materials provided with the distribution. | |||
* Neither the name of the copyright holder nor the | |||
names of its contributors may be used to endorse or promote products | |||
derived from this software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY | |||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
#include "brcmjpeg.h" | |||
#include <sys/time.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <errno.h> | |||
#include <stdio.h> | |||
#include <stdint.h> | |||
#include <user-vcsm.h> | |||
#define MAX_WIDTH 5000 | |||
#define MAX_HEIGHT 5000 | |||
#define MAX_ENCODED (15*1024*1024) | |||
#define MAX_DECODED (MAX_WIDTH*MAX_HEIGHT*2) | |||
static uint8_t encodedInBuf[MAX_ENCODED]; | |||
static uint8_t encodedOutBuf[MAX_ENCODED]; | |||
static uint8_t decodedBuf[MAX_DECODED]; | |||
static char outFileName[2048]; | |||
int64_t get_time_microsec(void) | |||
{ | |||
struct timeval now; | |||
gettimeofday(&now, NULL); | |||
return now.tv_sec * 1000000LL + now.tv_usec; | |||
} | |||
int main(int argc, char **argv) | |||
{ | |||
BRCMJPEG_STATUS_T status; | |||
BRCMJPEG_REQUEST_T enc_request, dec_request; | |||
BRCMJPEG_T *enc = 0, *dec = 0; | |||
int64_t start, stop, time_dec = 0, time_enc = 0; | |||
unsigned int count = 1, format = PIXEL_FORMAT_YUYV; | |||
unsigned int use_vcsm = 0, handle = 0, vc_handle = 0; | |||
int i, arg = 1, help = 0; | |||
// Parse command line arguments | |||
while (arg < argc && argv[arg][0] == '-') | |||
{ | |||
if (!strcmp(argv[arg], "-n")) | |||
{ | |||
if (++arg >= argc || sscanf(argv[arg++], "%u", &count) != 1) | |||
arg = argc; | |||
} | |||
else if (!strcmp(argv[arg], "-f")) | |||
{ | |||
if (++arg >= argc || sscanf(argv[arg++], "%u", &format) != 1) | |||
arg = argc; | |||
} | |||
else if (!strcmp(argv[arg], "-s")) | |||
{ | |||
use_vcsm = 1; | |||
arg++; | |||
} | |||
else if (!strcmp(argv[arg], "-h")) | |||
{ | |||
help = 1; | |||
break; | |||
} | |||
else | |||
{ | |||
arg = argc; | |||
} | |||
} | |||
if (arg == argc || help) | |||
{ | |||
if (!help) fprintf(stderr, "invalid arguments\n"); | |||
fprintf(stderr, "usage: %s [options] file1 ... fileN\n", argv[0]); | |||
fprintf(stderr, "options list:\n"); | |||
fprintf(stderr, " -h : help\n"); | |||
fprintf(stderr, " -n <N> : process each file N times\n"); | |||
fprintf(stderr, " -f <N> : force color format\n"); | |||
fprintf(stderr, " -s : use shared-memory for intermediate buffer\n"); | |||
return !help; | |||
} | |||
if (use_vcsm) | |||
{ | |||
if (vcsm_init() < 0) | |||
{ | |||
fprintf(stderr, "failed to initialise vcsm\n"); | |||
return 1; | |||
} | |||
handle = vcsm_malloc_cache(MAX_DECODED, VCSM_CACHE_TYPE_HOST, "brcmjpeg-test"); | |||
if (!handle) | |||
{ | |||
fprintf(stderr, "failed to alloc vcsm buffer\n"); | |||
vcsm_exit(); | |||
return 1; | |||
} | |||
vc_handle = vcsm_vc_hdl_from_hdl(handle); | |||
fprintf(stderr, "decodedBuf handle %u vc_handle %u\n", handle, vc_handle); | |||
} | |||
// Setup of the dec / enc requests | |||
memset(&enc_request, 0, sizeof(enc_request)); | |||
memset(&dec_request, 0, sizeof(dec_request)); | |||
dec_request.input = encodedInBuf; | |||
dec_request.output = use_vcsm ? NULL : decodedBuf; | |||
dec_request.output_handle = use_vcsm ? vc_handle : 0; | |||
dec_request.output_alloc_size = MAX_DECODED; | |||
enc_request.input = dec_request.output; | |||
enc_request.input_handle = dec_request.output_handle; | |||
enc_request.output = encodedOutBuf; | |||
enc_request.output_alloc_size = sizeof(encodedOutBuf); | |||
enc_request.quality = 75; | |||
enc_request.pixel_format = dec_request.pixel_format = format; | |||
status = brcmjpeg_create(BRCMJPEG_TYPE_ENCODER, &enc); | |||
if (status != BRCMJPEG_SUCCESS) | |||
{ | |||
fprintf(stderr, "could not create encoder\n"); | |||
return 1; | |||
} | |||
status = brcmjpeg_create(BRCMJPEG_TYPE_DECODER, &dec); | |||
if (status != BRCMJPEG_SUCCESS) | |||
{ | |||
fprintf(stderr, "could not create decoder\n"); | |||
brcmjpeg_release(enc); | |||
return 1; | |||
} | |||
for (i = arg; i < argc; i++) | |||
{ | |||
unsigned int j; | |||
fprintf(stderr, "processing %s\n", argv[i]); | |||
FILE *file_in = fopen(argv[i], "rb"); | |||
if (!file_in) { | |||
fprintf(stderr, "could not open file %s\n", argv[i]); | |||
continue; | |||
} | |||
snprintf(outFileName, sizeof(outFileName), "%s.out", argv[i]); | |||
FILE *file_out = fopen(outFileName, "wb+"); | |||
if (!file_out) { | |||
fprintf(stderr, "could not open file %s\n", outFileName); | |||
fclose(file_in); | |||
continue; | |||
} | |||
dec_request.input_size = fread(encodedInBuf, 1, sizeof(encodedInBuf), file_in); | |||
for (j = 0; j < count; j++) | |||
{ | |||
dec_request.buffer_width = 0; | |||
dec_request.buffer_height = 0; | |||
start = get_time_microsec(); | |||
status = brcmjpeg_process(dec, &dec_request); | |||
stop = get_time_microsec(); | |||
if (status != BRCMJPEG_SUCCESS) { | |||
fprintf(stderr, "could not decode %s\n", argv[i]); | |||
break; | |||
} | |||
fprintf(stderr, "decoded %ix%i(%ix%i), %i bytes in %lldus\n", | |||
dec_request.width, dec_request.height, | |||
dec_request.buffer_width, dec_request.buffer_height, | |||
dec_request.input_size, stop - start); | |||
time_dec += stop - start; | |||
enc_request.input_size = dec_request.output_size; | |||
enc_request.width = dec_request.width; | |||
enc_request.height = dec_request.height; | |||
enc_request.buffer_width = dec_request.buffer_width; | |||
enc_request.buffer_height = dec_request.buffer_height; | |||
start = get_time_microsec(); | |||
status = brcmjpeg_process(enc, &enc_request); | |||
stop = get_time_microsec(); | |||
if (status != BRCMJPEG_SUCCESS) { | |||
fprintf(stderr, "could not encode %s\n", outFileName); | |||
break; | |||
} | |||
fprintf(stderr, "encoded %ix%i(%ix%i), %i bytes in %lldus\n", | |||
enc_request.width, enc_request.height, | |||
enc_request.buffer_width, enc_request.buffer_height, | |||
enc_request.output_size, stop - start); | |||
time_enc += stop - start; | |||
} | |||
if (status != BRCMJPEG_SUCCESS) | |||
continue; | |||
fwrite(enc_request.output, 1, enc_request.output_size, file_out); | |||
fclose(file_out); | |||
fclose(file_in); | |||
fprintf(stderr, "decode times %lldus (%lldus per run)\n", | |||
time_dec, time_dec / count); | |||
fprintf(stderr, "encode times %lldus (%lldus per run)\n", | |||
time_enc, time_enc / count); | |||
} | |||
brcmjpeg_release(dec); | |||
brcmjpeg_release(enc); | |||
if (use_vcsm) | |||
{ | |||
vcsm_free(handle); | |||
vcsm_exit(); | |||
} | |||
return 0; | |||
} |
@@ -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) | |||
@@ -0,0 +1,504 @@ | |||
/* | |||
Copyright (c) 2012, Broadcom Europe Ltd | |||
All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright | |||
notice, this list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright | |||
notice, this list of conditions and the following disclaimer in the | |||
documentation and/or other materials provided with the distribution. | |||
* Neither the name of the copyright holder nor the | |||
names of its contributors may be used to endorse or promote products | |||
derived from this software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY | |||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
#include "mmal.h" | |||
#include "mmal_logging.h" | |||
#include "core/mmal_component_private.h" | |||
#include "core/mmal_port_private.h" | |||
#include "core/mmal_clock_private.h" | |||
#include <media/AudioTrack.h> | |||
#include <utils/Mutex.h> | |||
using namespace android; | |||
/* Buffering requirements */ | |||
#define INPUT_MIN_BUFFER_NUM 4 | |||
#define INPUT_RECOMMENDED_BUFFER_NUM 8 | |||
#define SPDIF_AC3_FRAME_SIZE 6144 | |||
/*****************************************************************************/ | |||
enum TRACK_STATE_T { | |||
TRACK_STATE_STOPPED, | |||
TRACK_STATE_RUNNING, | |||
TRACK_STATE_PAUSED | |||
}; | |||
typedef struct MMAL_COMPONENT_MODULE_T | |||
{ | |||
MMAL_STATUS_T status; | |||
MMAL_QUEUE_T *queue; | |||
android::sp<android::AudioTrack> track; | |||
Mutex *lock; | |||
uint32_t bytes_queued; | |||
MMAL_BOOL_T is_enabled; | |||
TRACK_STATE_T state; | |||
MMAL_ES_FORMAT_T *format; /**< format currently configured */ | |||
} MMAL_COMPONENT_MODULE_T; | |||
/*****************************************************************************/ | |||
static void aaf_track_callback(int event, void *user, void *info); | |||
static struct encoding_table_t { | |||
MMAL_FOURCC_T encoding; | |||
audio_format_t format; | |||
} encoding_list[] = | |||
{ {MMAL_ENCODING_PCM_SIGNED, AUDIO_FORMAT_PCM_16_BIT}, | |||
#ifdef ANDROID_SUPPORTS_AC3 | |||
{MMAL_ENCODING_AC3, AUDIO_FORMAT_AC3_SPDIF}, | |||
{MMAL_ENCODING_EAC3, AUDIO_FORMAT_EAC3_SPDIF}, | |||
#endif | |||
{0, AUDIO_FORMAT_INVALID} | |||
}; | |||
static audio_format_t encoding_to_audio_format(MMAL_FOURCC_T encoding) | |||
{ | |||
struct encoding_table_t *entry = encoding_list; | |||
for (entry = encoding_list; entry->encoding; entry++) | |||
if (entry->encoding == encoding) | |||
break; | |||
return entry->format; | |||
} | |||
static void aaf_track_destroy(MMAL_COMPONENT_T *component) | |||
{ | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
if (module->track != NULL) | |||
{ | |||
module->track->stop(); | |||
module->track = NULL; | |||
} | |||
} | |||
static MMAL_STATUS_T aaf_track_create(MMAL_COMPONENT_T *component) | |||
{ | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
MMAL_PORT_T *port = component->input[0]; | |||
audio_channel_mask_t channels_mask; | |||
int frame_count = 256; | |||
/* Reset track on format change. Can do better than that? */ | |||
if (module->track != NULL) | |||
aaf_track_destroy(component); | |||
channels_mask = audio_channel_out_mask_from_count(port->format->es->audio.channels); | |||
LOG_INFO("%s(%p) %4.4s, %i Hz, mask %x, chan %i", port->name, port, | |||
(char *)&port->format->encoding, | |||
(int)port->format->es->audio.sample_rate, channels_mask, | |||
(int)port->format->es->audio.channels); | |||
AudioTrack::getMinFrameCount(&frame_count); | |||
if (port->format->encoding == MMAL_ENCODING_AC3) | |||
frame_count = SPDIF_AC3_FRAME_SIZE; | |||
else if (port->format->encoding == MMAL_ENCODING_EAC3) | |||
frame_count = SPDIF_AC3_FRAME_SIZE * 4; | |||
frame_count *= 2; /* Twice the minimum should be enough */ | |||
module->track = new AudioTrack(AUDIO_STREAM_MUSIC, | |||
port->format->es->audio.sample_rate, | |||
encoding_to_audio_format(port->format->encoding), channels_mask, | |||
frame_count, port->format->encoding == MMAL_ENCODING_PCM_SIGNED ? | |||
AUDIO_OUTPUT_FLAG_NONE : AUDIO_OUTPUT_FLAG_DIRECT, | |||
&aaf_track_callback, port, 0); | |||
if (module->track == NULL || module->track->initCheck() != OK) | |||
{ | |||
LOG_ERROR("%s(%p): track creation failed", port->name, port); | |||
module->track = NULL; | |||
return MMAL_ENOSYS; | |||
} | |||
return MMAL_SUCCESS; | |||
} | |||
static void aaf_track_callback(int event, void *user, void *info) | |||
{ | |||
MMAL_PORT_T *port = (MMAL_PORT_T *)user; | |||
MMAL_COMPONENT_T *component = port->component; | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
MMAL_BUFFER_HEADER_T *buffer; | |||
AudioTrack::Buffer *trackbuf = NULL; | |||
unsigned int bytes, space; | |||
uint8_t *dest; | |||
if (event == AudioTrack::EVENT_UNDERRUN) | |||
LOG_ERROR("underrun"); | |||
if (event != AudioTrack::EVENT_MORE_DATA) | |||
return; | |||
trackbuf = (AudioTrack::Buffer *)info; | |||
space = trackbuf->size; | |||
dest = (uint8_t *)trackbuf->raw; | |||
trackbuf->size = 0; | |||
if (!mmal_queue_length(module->queue)) | |||
{ | |||
LOG_ERROR("no buffers queued"); | |||
return; | |||
} | |||
while (space > 0) | |||
{ | |||
buffer = mmal_queue_get(module->queue); | |||
if (!buffer) | |||
break; | |||
bytes = MMAL_MIN(buffer->length, space); | |||
memcpy(dest, buffer->data + buffer->offset, bytes); | |||
buffer->offset += bytes; | |||
buffer->length -= bytes; | |||
dest += bytes; | |||
space -= bytes; | |||
trackbuf->size += bytes; | |||
if (buffer->length) | |||
{ | |||
/* Re-queue */ | |||
mmal_queue_put_back(module->queue, buffer); | |||
continue; | |||
} | |||
/* Handle the EOS */ | |||
if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS) | |||
mmal_event_eos_send(port); | |||
buffer->offset = 0; | |||
mmal_port_buffer_header_callback(port, buffer); | |||
} | |||
module->lock->lock(); | |||
module->bytes_queued -= trackbuf->size; | |||
module->lock->unlock(); | |||
} | |||
static MMAL_STATUS_T aaf_track_state_update(MMAL_COMPONENT_T *component) | |||
{ | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
TRACK_STATE_T new_state = TRACK_STATE_STOPPED; | |||
if (module->track == NULL) | |||
return MMAL_SUCCESS; | |||
if (module->is_enabled) | |||
{ | |||
MMAL_RATIONAL_T scale = mmal_port_clock_scale_get(component->clock[0]); | |||
new_state = TRACK_STATE_PAUSED; | |||
if (scale.den && scale.den == scale.num) | |||
new_state = TRACK_STATE_RUNNING; | |||
} | |||
if (new_state == module->state) | |||
return MMAL_SUCCESS; /* Nothing to do */ | |||
if (module->state == TRACK_STATE_STOPPED && new_state == TRACK_STATE_RUNNING) | |||
{ | |||
module->track->start(); | |||
} | |||
else if (module->state == TRACK_STATE_RUNNING) | |||
{ | |||
if (new_state == TRACK_STATE_STOPPED) | |||
module->track->stop(); | |||
else if (new_state == TRACK_STATE_PAUSED) | |||
module->track->pause(); | |||
} | |||
else if (module->state == TRACK_STATE_PAUSED) | |||
{ | |||
if (new_state == TRACK_STATE_STOPPED) | |||
module->track->stop(); | |||
else if (new_state == TRACK_STATE_RUNNING) | |||
module->track->start(); | |||
} | |||
module->state = new_state; | |||
return MMAL_SUCCESS; | |||
} | |||
/** Destroy a previously created component */ | |||
static MMAL_STATUS_T aaf_component_destroy(MMAL_COMPONENT_T *component) | |||
{ | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
aaf_track_destroy(component); | |||
if(component->input_num) | |||
mmal_ports_free(component->input, component->input_num); | |||
if(component->clock_num) | |||
mmal_ports_clock_free(component->clock, component->clock_num); | |||
if(module->format) | |||
mmal_format_free(module->format); | |||
if(module->queue) | |||
mmal_queue_destroy(module->queue); | |||
delete module->lock; | |||
vcos_free(module); | |||
return MMAL_SUCCESS; | |||
} | |||
/** Set format on a port */ | |||
static MMAL_STATUS_T aaf_port_set_format(MMAL_PORT_T *port) | |||
{ | |||
MMAL_COMPONENT_T *component = port->component; | |||
if (!mmal_format_compare(port->format, component->priv->module->format)) | |||
return MMAL_SUCCESS; | |||
/* Check the format is supported */ | |||
if (encoding_to_audio_format(port->format->encoding) == AUDIO_FORMAT_INVALID) | |||
{ | |||
LOG_ERROR("port does not support '%4.4s'", (char *)&port->format->encoding); | |||
return MMAL_EINVAL; | |||
} | |||
/* Specific checks for PCM */ | |||
if (port->format->encoding == MMAL_ENCODING_PCM_SIGNED) | |||
{ | |||
if (port->format->es->audio.bits_per_sample != 16 && | |||
port->format->es->audio.bits_per_sample != 32) | |||
{ | |||
LOG_ERROR("port does not support '%4.4s' at %ibps", | |||
(char *)&port->format->encoding, | |||
port->format->es->audio.bits_per_sample); | |||
return MMAL_EINVAL; | |||
} | |||
if (!audio_channel_out_mask_from_count(port->format->es->audio.channels)) | |||
{ | |||
LOG_ERROR("%s invalid channels mask from %i", port->name, | |||
(int)port->format->es->audio.channels); | |||
return MMAL_ENOSYS; | |||
} | |||
} | |||
mmal_format_copy(component->priv->module->format, port->format); | |||
return aaf_track_create(component); | |||
} | |||
/** Enable processing on a port */ | |||
static MMAL_STATUS_T aaf_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb) | |||
{ | |||
MMAL_COMPONENT_T *component = port->component; | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
MMAL_STATUS_T status = MMAL_SUCCESS; | |||
MMAL_PARAM_UNUSED(cb); | |||
if (module->track == NULL) | |||
status = aaf_port_set_format(port); | |||
if (status != MMAL_SUCCESS) | |||
return status; | |||
module->is_enabled = MMAL_TRUE; | |||
aaf_track_state_update(component); | |||
return MMAL_SUCCESS; | |||
} | |||
/** Flush a port */ | |||
static MMAL_STATUS_T aaf_port_flush(MMAL_PORT_T *port) | |||
{ | |||
MMAL_COMPONENT_T *component = port->component; | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
MMAL_BUFFER_HEADER_T *buffer; | |||
while((buffer = mmal_queue_get(module->queue))) | |||
mmal_port_buffer_header_callback(port, buffer); | |||
module->lock->lock(); | |||
module->bytes_queued = 0; | |||
module->lock->unlock(); | |||
if (module->track == NULL) | |||
return MMAL_SUCCESS; | |||
module->track->stop(); | |||
module->track->flush(); | |||
module->state = TRACK_STATE_STOPPED; | |||
aaf_track_state_update(component); | |||
return MMAL_SUCCESS; | |||
} | |||
/** Disable processing on a port */ | |||
static MMAL_STATUS_T aaf_port_disable(MMAL_PORT_T *port) | |||
{ | |||
MMAL_COMPONENT_T *component = port->component; | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
module->is_enabled = MMAL_FALSE; | |||
aaf_track_state_update(component); | |||
return aaf_port_flush(port); | |||
} | |||
static MMAL_STATUS_T aaf_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) | |||
{ | |||
MMAL_COMPONENT_T *component = port->component; | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
unsigned int bits_per_sample, channels, sample_rate; | |||
uint32_t aaf_bytes_queued = 0; | |||
int64_t latency, ts; | |||
/* Handle event buffers */ | |||
if (buffer->cmd) | |||
{ | |||
LOG_ERROR("discarding event %i on port %p", (int)buffer->cmd, port); | |||
buffer->length = 0; | |||
mmal_port_buffer_header_callback(port, buffer); | |||
return MMAL_SUCCESS; | |||
} | |||
if (module->status != MMAL_SUCCESS) | |||
return module->status; | |||
bits_per_sample = port->format->es->audio.bits_per_sample; | |||
channels = port->format->es->audio.channels; | |||
sample_rate = port->format->es->audio.sample_rate; | |||
if (port->format->encoding == MMAL_ENCODING_AC3 || | |||
port->format->encoding == MMAL_ENCODING_EAC3) | |||
{ | |||
uint32_t aaf_latency = 0; | |||
AudioSystem::getOutputLatency(&aaf_latency, AUDIO_STREAM_MUSIC); | |||
latency = aaf_latency * 1000LL; | |||
bits_per_sample = 16; | |||
channels = 2; | |||
if (port->format->encoding == MMAL_ENCODING_EAC3 && | |||
sample_rate <= 48000) | |||
sample_rate *= 4; | |||
aaf_bytes_queued = module->track->frameCount(); | |||
} | |||
else | |||
{ | |||
latency = module->track->latency() * 1000LL; | |||
} | |||
/* Keep aaf_track_callback from sending more samples */ | |||
module->lock->lock(); | |||
module->bytes_queued += buffer->length; | |||
latency += (module->bytes_queued + aaf_bytes_queued) / channels / | |||
(bits_per_sample / 8) * 1000000LL / sample_rate; | |||
ts = buffer->pts - latency; | |||
module->lock->unlock(); | |||
mmal_port_clock_media_time_set(component->clock[0], ts); | |||
mmal_queue_put(module->queue, buffer); | |||
return MMAL_SUCCESS; | |||
} | |||
void aaf_clock_event(MMAL_PORT_T *port, const MMAL_CLOCK_EVENT_T *event) | |||
{ | |||
MMAL_COMPONENT_T *component = port->component; | |||
switch (event->id) | |||
{ | |||
case MMAL_CLOCK_EVENT_SCALE: | |||
aaf_track_state_update(component); | |||
break; | |||
case MMAL_CLOCK_EVENT_TIME: | |||
case MMAL_CLOCK_EVENT_REFERENCE: | |||
case MMAL_CLOCK_EVENT_ACTIVE: | |||
/* nothing to do */ | |||
break; | |||
default: | |||
LOG_DEBUG("unknown event id %4.4s", (char*)&event->id); | |||
break; | |||
} | |||
} | |||
/** Create an instance of a component */ | |||
static MMAL_STATUS_T mmal_component_create_aaf(const char *name, MMAL_COMPONENT_T *component) | |||
{ | |||
MMAL_COMPONENT_MODULE_T *module; | |||
/* Check we're the requested component */ | |||
if(strcmp(name, "aaf." MMAL_AUDIO_RENDER)) | |||
return MMAL_ENOENT; | |||
/* Allocate our module context */ | |||
component->priv->module = module = (MMAL_COMPONENT_MODULE_T *)vcos_calloc(1, sizeof(*module), "mmal module"); | |||
if(!module) | |||
return MMAL_ENOMEM; | |||
module->lock = new Mutex(); | |||
if (!module->lock) | |||
goto error; | |||
/* Allocate the ports for this component */ | |||
component->input = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_INPUT, 0); | |||
if(!component->input) | |||
goto error; | |||
component->input_num = 1; | |||
/* Create the clock port (clock ports are managed by the framework) */ | |||
component->clock = mmal_ports_clock_alloc(component, 1, 0, aaf_clock_event); | |||
if (!component->clock) | |||
goto error; | |||
component->clock_num = 1; | |||
module->queue = mmal_queue_create(); | |||
if(!module->queue) | |||
goto error; | |||
module->format = mmal_format_alloc(); | |||
if(!module->format) | |||
goto error; | |||
component->input[0]->priv->pf_set_format = aaf_port_set_format; | |||
component->input[0]->priv->pf_enable = aaf_port_enable; | |||
component->input[0]->priv->pf_disable = aaf_port_disable; | |||
component->input[0]->priv->pf_flush = aaf_port_flush; | |||
component->input[0]->priv->pf_send = aaf_port_send; | |||
component->input[0]->buffer_num_min = INPUT_MIN_BUFFER_NUM; | |||
component->input[0]->buffer_num_recommended = INPUT_RECOMMENDED_BUFFER_NUM; | |||
component->input[0]->format->type = MMAL_ES_TYPE_AUDIO; | |||
component->priv->pf_destroy = aaf_component_destroy; | |||
return MMAL_SUCCESS; | |||
error: | |||
aaf_component_destroy(component); | |||
return MMAL_ENOMEM; | |||
} | |||
MMAL_CONSTRUCTOR(mmal_register_component_aaf_audio); | |||
void mmal_register_component_aaf_audio(void) | |||
{ | |||
mmal_component_supplier_register("aaf", mmal_component_create_aaf); | |||
} |
@@ -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); | |||
} |
@@ -0,0 +1,861 @@ | |||
/* | |||
Copyright (c) 2012, Broadcom Europe Ltd | |||
All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright | |||
notice, this list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright | |||
notice, this list of conditions and the following disclaimer in the | |||
documentation and/or other materials provided with the distribution. | |||
* Neither the name of the copyright holder nor the | |||
names of its contributors may be used to endorse or promote products | |||
derived from this software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY | |||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
#include "mmal.h" | |||
#include "core/mmal_component_private.h" | |||
#include "core/mmal_port_private.h" | |||
#include "mmal_logging.h" | |||
#include <media/stagefright/MediaCodec.h> | |||
#include <media/stagefright/MediaErrors.h> | |||
#include <media/stagefright/foundation/ABuffer.h> | |||
#include <media/stagefright/foundation/AMessage.h> | |||
#include <media/ICrypto.h> | |||
#include <gui/ISurfaceComposer.h> | |||
#include <gui/SurfaceComposerClient.h> | |||
#include <binder/ProcessState.h> | |||
using namespace android; | |||
/* List of variants supported by this component */ | |||
#define AMC_VARIANT_UNKNOWN 0 | |||
#define AMC_VARIANT_AUDIO_DECODE 1 | |||
#define AMC_VARIANT_AUDIO_DECODE_NAME "audio_decode" | |||
/*****************************************************************************/ | |||
struct AmcHandler : public AHandler | |||
{ | |||
AmcHandler(MMAL_COMPONENT_T *component) : | |||
mComponent(component), mNotificationRequested(false) {} | |||
void requestNotification(sp<MediaCodec> &codec) | |||
{ | |||
if (mActivityNotify == NULL) | |||
mActivityNotify = new AMessage(0, id()); | |||
if (!mNotificationRequested) | |||
{ | |||
mNotificationRequested = true; | |||
codec->requestActivityNotification(mActivityNotify->dup()); | |||
} | |||
} | |||
void reset() | |||
{ | |||
mNotificationRequested = false; | |||
} | |||
protected: | |||
virtual void onMessageReceived(const sp<AMessage> &msg) | |||
{ | |||
(void)msg; | |||
mNotificationRequested = false; | |||
mmal_component_action_trigger(mComponent); | |||
} | |||
private: | |||
MMAL_COMPONENT_T *mComponent; | |||
sp<AMessage> mActivityNotify; | |||
bool mNotificationRequested; | |||
}; | |||
typedef struct MMAL_COMPONENT_MODULE_T | |||
{ | |||
MMAL_STATUS_T status; /**< current status of the component */ | |||
sp<MediaCodec> codec; | |||
sp<AmcHandler> ahandler; | |||
sp<ALooper> alooper; | |||
Vector<sp<ABuffer> > input_buffers; /**< list of buffers exported by mediacodec */ | |||
Vector<sp<ABuffer> > output_buffers; /**< list of buffers exported by mediacodec */ | |||
} MMAL_COMPONENT_MODULE_T; | |||
typedef struct MMAL_PORT_MODULE_T | |||
{ | |||
MMAL_ES_FORMAT_T *format; /**< format currently configured */ | |||
MMAL_QUEUE_T *queue; /**< queue for the buffers sent to the ports */ | |||
MMAL_BOOL_T needs_configuring; /**< port is waiting for a format commit */ | |||
List<size_t> *dequeued; /* buffers already dequeued from the codec */ | |||
const char *mime; | |||
unsigned int actual_channels; | |||
} MMAL_PORT_MODULE_T; | |||
static struct encoding_table_t { | |||
const char *mime; | |||
MMAL_FOURCC_T encoding; | |||
MMAL_ES_TYPE_T type; | |||
MMAL_FOURCC_T encoding_variant; | |||
} encoding_list[] = | |||
{ {"audio/3gpp", MMAL_ENCODING_AMRNB, MMAL_ES_TYPE_AUDIO, 0}, | |||
{"audio/amr-wb", MMAL_ENCODING_AMRWB, MMAL_ES_TYPE_AUDIO, 0}, | |||
{"audio/mpeg", MMAL_ENCODING_MPGA, MMAL_ES_TYPE_AUDIO, 0}, | |||
{"audio/mp4a-latm", MMAL_ENCODING_MP4A, MMAL_ES_TYPE_AUDIO, 0}, | |||
{"audio/mp4a-latm", MMAL_ENCODING_MP4A, MMAL_ES_TYPE_AUDIO, MMAL_ENCODING_VARIANT_MP4A_ADTS}, | |||
{"audio/vorbis", MMAL_ENCODING_VORBIS, MMAL_ES_TYPE_AUDIO, 0}, | |||
{"audio/g711-alaw", MMAL_ENCODING_ALAW, MMAL_ES_TYPE_AUDIO, 0}, | |||
{"audio/g711-ulaw", MMAL_ENCODING_MULAW, MMAL_ES_TYPE_AUDIO, 0}, | |||
{"audio/ac3", MMAL_ENCODING_AC3, MMAL_ES_TYPE_AUDIO, 0}, | |||
{"audio/ec3", MMAL_ENCODING_EAC3, MMAL_ES_TYPE_AUDIO, 0}, | |||
{"audio/eac3", MMAL_ENCODING_EAC3, MMAL_ES_TYPE_AUDIO, 0}, | |||
{"audio/raw", MMAL_ENCODING_PCM_SIGNED, MMAL_ES_TYPE_AUDIO, 0}, | |||
{"", MMAL_ENCODING_PCM_SIGNED, MMAL_ES_TYPE_AUDIO, 0}, | |||
{ 0, 0, MMAL_ES_TYPE_UNKNOWN, 0} | |||
}; | |||
static const char *encoding_to_mime(MMAL_ES_TYPE_T type, MMAL_FOURCC_T encoding, | |||
MMAL_FOURCC_T encoding_variant) | |||
{ | |||
struct encoding_table_t *entry = encoding_list; | |||
for (entry = encoding_list; entry->mime; entry++) | |||
if (entry->encoding == encoding && entry->type == type && | |||
entry->encoding_variant == encoding_variant) | |||
break; | |||
return entry->mime; | |||
} | |||
static void mime_to_encoding(const char *mime, | |||
MMAL_ES_TYPE_T *type, MMAL_FOURCC_T *encoding, MMAL_FOURCC_T *encoding_variant) | |||
{ | |||
struct encoding_table_t *entry = encoding_list; | |||
for (entry = encoding_list; entry->mime; entry++) | |||
if (!strcmp(mime, entry->mime)) | |||
break; | |||
*encoding = entry->encoding; | |||
*type = entry->type; | |||
*encoding_variant = entry->encoding_variant; | |||
} | |||
/*****************************************************************************/ | |||
/** Actual processing functions */ | |||
static MMAL_BOOL_T amc_do_input_processing(MMAL_COMPONENT_T *component, | |||
MMAL_BOOL_T *notification) | |||
{ | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
MMAL_PORT_T *port = component->input[0]; | |||
MMAL_PORT_MODULE_T *port_module = port->priv->module; | |||
MMAL_BUFFER_HEADER_T *in; | |||
status_t astatus; | |||
size_t size, index; | |||
uint32_t flags = 0; | |||
in = mmal_queue_get(port_module->queue); | |||
/* Get an input buffer from the codec. We dequeue input buffers even | |||
* if we do not any data to process to make sure that we do not get | |||
* flooded with notifications from the codec that buffers are | |||
* available. */ | |||
if (port_module->dequeued->empty() || !in) | |||
{ | |||
astatus = module->codec->dequeueInputBuffer(&index, 0ll); | |||
if (astatus == OK) | |||
{ | |||
LOG_TRACE("dequeueInputBuffer %i", index); | |||
port_module->dequeued->push_back(index); | |||
} | |||
else if (astatus != -EAGAIN) | |||
{ | |||
LOG_TRACE("dequeueInputBuffer failed (%i)", astatus); | |||
} | |||
} | |||
/* Check whether we can process data */ | |||
if (!in) | |||
{ | |||
return 0; | |||
} | |||
else if (port_module->dequeued->empty()) | |||
{ | |||
mmal_queue_put_back(port_module->queue, in); | |||
/* We have data we want to process so request to be notified as soon | |||
* as the codec is available to process it */ | |||
*notification |= MMAL_TRUE; | |||
return 0; | |||
} | |||
/* We have some processing to do */ | |||
index = *port_module->dequeued->begin(); | |||
sp<ABuffer> inBuf = module->input_buffers.itemAt(index); | |||
if (inBuf->capacity() < in->length) | |||
LOG_ERROR("MediaCodec input buffer too small (%i/%i)", | |||
(int)inBuf->capacity(), (int)in->length); | |||
size = MMAL_MIN(inBuf->capacity(), in->length); | |||
if (in->length) | |||
memcpy(inBuf->data(), in->data + in->offset, size); | |||
if (in->flags & MMAL_BUFFER_HEADER_FLAG_EOS) | |||
flags |= MediaCodec::BUFFER_FLAG_EOS; | |||
if (in->flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME) | |||
flags |= MediaCodec::BUFFER_FLAG_SYNCFRAME; | |||
if (in->flags & MMAL_BUFFER_HEADER_FLAG_CONFIG) | |||
flags |= MediaCodec::BUFFER_FLAG_CODECCONFIG; | |||
LOG_TRACE("queueInputBuffer %i %ibytes, %lldus", index, in->length, in->pts); | |||
astatus = module->codec->queueInputBuffer(index, 0, size, in->pts, flags); | |||
if (astatus != OK) | |||
{ | |||
LOG_ERROR("queueInputBuffer failed (%i)", astatus); | |||
mmal_event_error_send(component, MMAL_EIO); | |||
module->status = MMAL_EIO; | |||
} | |||
/* Send buffers back */ | |||
in->length = 0; | |||
mmal_port_buffer_header_callback(port, in); | |||
port_module->dequeued->erase(port_module->dequeued->begin()); | |||
return 1; | |||
} | |||
static void amc_output_format_changed(MMAL_COMPONENT_T *component) | |||
{ | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
MMAL_PORT_T *port = component->output[0]; | |||
MMAL_EVENT_FORMAT_CHANGED_T *event; | |||
MMAL_BUFFER_HEADER_T *buffer; | |||
MMAL_STATUS_T status; | |||
int32_t value; | |||
sp<AMessage> format = new AMessage; | |||
status_t astatus = module->codec->getOutputFormat(&format); | |||
LOG_DEBUG("INFO_FORMAT_CHANGED (%i): %s", astatus, | |||
format->debugString().c_str()); | |||
/* Get an event buffer */ | |||
status = mmal_port_event_get(port, &buffer, MMAL_EVENT_FORMAT_CHANGED); | |||
if (status != MMAL_SUCCESS) | |||
{ | |||
LOG_ERROR("unable to get an event buffer"); | |||
return; | |||
} | |||
event = mmal_event_format_changed_get(buffer); | |||
AString amime; | |||
format->findString("mime", &amime); | |||
mime_to_encoding(amime.c_str(), | |||
&event->format->type, &event->format->encoding, | |||
&event->format->encoding_variant); | |||
switch (port->format->type) | |||
{ | |||
case MMAL_ES_TYPE_VIDEO: | |||
if (format->findInt32("width", &value)) | |||
event->format->es->video.width = value; | |||
if (format->findInt32("height", &value)) | |||
event->format->es->video.height = value; | |||
break; | |||
case MMAL_ES_TYPE_AUDIO: | |||
if (format->findInt32("channel-count", &value)) | |||
event->format->es->audio.channels = value; | |||
if (format->findInt32("sample-rate", &value)) | |||
event->format->es->audio.sample_rate = value; | |||
if (format->findInt32("bitrate", &value)) | |||
event->format->bitrate = value; | |||
if (event->format->encoding == MMAL_ENCODING_PCM_SIGNED) | |||
event->format->es->audio.bits_per_sample = 16; | |||
break; | |||
default: | |||
break; | |||
} | |||
/* Work-around for the ril audio_render component which only supports | |||
* power of 2 arrangements */ | |||
if (event->format->type == MMAL_ES_TYPE_AUDIO && | |||
event->format->encoding == MMAL_ENCODING_PCM_SIGNED) | |||
{ | |||
port->priv->module->actual_channels = event->format->es->audio.channels; | |||
if (event->format->es->audio.channels == 6) | |||
event->format->es->audio.channels = 8; | |||
} | |||
/* Update current format */ | |||
mmal_format_copy(port->priv->module->format, event->format); | |||
/* Pass on the buffer requirements */ | |||
event->buffer_num_min = port->buffer_num_min; | |||
event->buffer_size_min = port->buffer_size_min; | |||
event->buffer_size_recommended = port->buffer_size_recommended; | |||
event->buffer_num_recommended = port->buffer_num_recommended; | |||
mmal_port_event_send(port, buffer); | |||
} | |||
static MMAL_BOOL_T amc_do_output_processing(MMAL_COMPONENT_T *component, | |||
MMAL_BOOL_T *notification) | |||
{ | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
MMAL_PORT_T *port_out = component->output[0]; | |||
MMAL_BUFFER_HEADER_T *out; | |||
status_t astatus; | |||
size_t size, offset, index; | |||
int64_t pts; | |||
uint32_t flags; | |||
if (port_out->priv->module->needs_configuring) | |||
return 0; | |||
out = mmal_queue_get(port_out->priv->module->queue); | |||
if (!out) | |||
{ | |||
/* We do not want notifications in that case. We've already filled | |||
* our output buffers so we should really wait to receive more | |||
* output buffers before resuming the processing */ | |||
*notification = MMAL_FALSE; | |||
return 0; | |||
} | |||
out->flags = 0; | |||
astatus = module->codec->dequeueOutputBuffer(&index, &offset, &size, &pts, &flags, 0ll); | |||
if (astatus != OK) | |||
{ | |||
MMAL_BOOL_T do_more = 0; | |||
switch (astatus) | |||
{ | |||
case INFO_OUTPUT_BUFFERS_CHANGED: | |||
LOG_DEBUG("INFO_OUTPUT_BUFFERS_CHANGED"); | |||
astatus = module->codec->getOutputBuffers(&module->output_buffers); | |||
do_more = MMAL_TRUE; | |||
break; | |||
case INFO_FORMAT_CHANGED: | |||
amc_output_format_changed(component); | |||
port_out->priv->module->needs_configuring = 1; | |||
do_more = MMAL_TRUE; | |||
break; | |||
case -EAGAIN: | |||
/* We have data we want to process so request to be notified as soon | |||
* as the codec is available to process it */ | |||
*notification |= MMAL_TRUE; | |||
break; | |||
default: | |||
LOG_ERROR("dequeueOutputBuffer failed (%i)", astatus); | |||
} | |||
mmal_queue_put_back(port_out->priv->module->queue, out); | |||
return do_more; | |||
} | |||
LOG_TRACE("dequeueOutputBuffer %i, %ibytes, %lldus, flags %x", | |||
index, size, pts, flags); | |||
sp<ABuffer> outBuf = module->output_buffers.itemAt(index); | |||
out->flags = 0; | |||
out->offset = 0; | |||
out->pts = pts; | |||
out->dts = 0; | |||
if (flags & MediaCodec::BUFFER_FLAG_EOS) | |||
out->flags |= MMAL_BUFFER_HEADER_FLAG_EOS; | |||
if (flags & MediaCodec::BUFFER_FLAG_SYNCFRAME) | |||
out->flags |= MMAL_BUFFER_HEADER_FLAG_KEYFRAME; | |||
if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) | |||
out->flags |= MMAL_BUFFER_HEADER_FLAG_CONFIG; | |||
if (out->alloc_size < size) | |||
LOG_ERROR("MediaCodec output buffer too big (%i/%i)", | |||
(int)out->alloc_size, (int)size); | |||
size = MMAL_MIN(out->alloc_size, size); | |||
/* Audio render only accepts power of 2 channel configurations */ | |||
if (port_out->format->type == MMAL_ES_TYPE_AUDIO && | |||
port_out->format->encoding == MMAL_ENCODING_PCM_SIGNED && | |||
port_out->priv->module->actual_channels != | |||
port_out->format->es->audio.channels) | |||
{ | |||
unsigned int valid = port_out->priv->module->actual_channels * 2; | |||
unsigned int pitch = port_out->format->es->audio.channels * 2; | |||
uint8_t *src = outBuf->data() + offset; | |||
uint8_t *dst = out->data; | |||
unsigned int i; | |||
size = size * port_out->format->es->audio.channels / | |||
port_out->priv->module->actual_channels; | |||
size = MMAL_MIN(out->alloc_size, size); | |||
memset(dst, 0, size); | |||
for (i = size / pitch; i; i--, src += valid, dst += pitch) | |||
memcpy(dst, src, valid); | |||
} | |||
else if (size) | |||
memcpy(out->data, outBuf->data() + offset, size); | |||
out->length = size; | |||
/* Send buffers back */ | |||
module->codec->releaseOutputBuffer(index); | |||
mmal_port_buffer_header_callback(port_out, out); | |||
return 1; | |||
} | |||
static MMAL_BOOL_T amc_do_processing(MMAL_COMPONENT_T *component) | |||
{ | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
MMAL_BOOL_T do_more, request_notification = MMAL_FALSE; | |||
if (module->codec == NULL) | |||
return 0; | |||
/* Don't do anything if we've already seen an error */ | |||
if (module->status != MMAL_SUCCESS) | |||
return 0; | |||
do_more = amc_do_input_processing(component, &request_notification); | |||
do_more |= amc_do_output_processing(component, &request_notification); | |||
if (request_notification) | |||
module->ahandler->requestNotification(module->codec); | |||
return do_more; | |||
} | |||
/*****************************************************************************/ | |||
static void amc_do_processing_loop(MMAL_COMPONENT_T *component) | |||
{ | |||
while (amc_do_processing(component)); | |||
} | |||
/** Destroy a previously created component */ | |||
static MMAL_STATUS_T amc_component_destroy(MMAL_COMPONENT_T *component) | |||
{ | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
unsigned int i; | |||
for(i = 0; i < component->input_num; i++) | |||
{ | |||
if(component->input[i]->priv->module->queue) | |||
mmal_queue_destroy(component->input[i]->priv->module->queue); | |||
if(component->input[i]->priv->module->format) | |||
mmal_format_free(component->input[i]->priv->module->format); | |||
if(component->input[i]->priv->module->dequeued) | |||
delete component->input[i]->priv->module->dequeued; | |||
} | |||
if(component->input_num) | |||
mmal_ports_free(component->input, component->input_num); | |||
for(i = 0; i < component->output_num; i++) | |||
{ | |||
if(component->output[i]->priv->module->queue) | |||
mmal_queue_destroy(component->output[i]->priv->module->queue); | |||
if(component->output[i]->priv->module->format) | |||
mmal_format_free(component->output[i]->priv->module->format); | |||
} | |||
if(component->output_num) | |||
mmal_ports_free(component->output, component->output_num); | |||
if (module->codec != NULL) | |||
{ | |||
module->codec->stop(); | |||
module->codec->release(); | |||
} | |||
module->alooper->unregisterHandler(module->ahandler->id()); | |||
module->alooper->stop(); | |||
delete module; | |||
return MMAL_SUCCESS; | |||
} | |||
static MMAL_STATUS_T amc_codec_start(MMAL_COMPONENT_T *component) | |||
{ | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
MMAL_PORT_T *in = component->input[0]; | |||
sp<AMessage> format = new AMessage; | |||
status_t astatus; | |||
const char *mime; | |||
mime = encoding_to_mime(in->format->type, in->format->encoding, | |||
in->format->encoding_variant); | |||
if (!mime) | |||
{ | |||
LOG_ERROR("cannot match codec %4.4s(%4.4s) with a mime type", | |||
(char *)&in->format->encoding, (char *)&in->format->encoding_variant); | |||
return MMAL_EINVAL; | |||
} | |||
/* We need to restart MediaCodec when the codec type changes */ | |||
if (module->codec == NULL || mime != in->priv->module->mime) | |||
{ | |||
LOG_DEBUG("creating codec for %s", mime); | |||
/* Start by releasing any instance we've previously created */ | |||
if (module->codec != NULL) | |||
{ | |||
module->codec->stop(); | |||
module->codec->release(); | |||
} | |||
module->codec = MediaCodec::CreateByType(module->alooper, mime, false); | |||
if (module->codec == NULL) | |||
{ | |||
LOG_ERROR("cannot instantiate MediaCodec for mime: %s", mime); | |||
return MMAL_EINVAL; | |||
} | |||
in->priv->module->mime = mime; | |||
module->ahandler->reset(); | |||
LOG_TRACE("creation done"); | |||
} | |||
/* When reusing an existing instance, we just need to stop it */ | |||
else | |||
{ | |||
module->codec->stop(); | |||
} | |||
/* Configure MediaCodec */ | |||
switch (in->format->type) | |||
{ | |||
case MMAL_ES_TYPE_VIDEO: | |||
format->setInt32("width", in->format->es->video.width); | |||
format->setInt32("height", in->format->es->video.height); | |||
if (in->format->es->video.frame_rate.num && in->format->es->video.frame_rate.den) | |||
format->setFloat("frame-rate", in->format->es->video.frame_rate.num / | |||
(float)in->format->es->video.frame_rate.den); | |||
break; | |||
case MMAL_ES_TYPE_AUDIO: | |||
format->setInt32("channel-count", in->format->es->audio.channels); | |||
format->setInt32("sample-rate", in->format->es->audio.sample_rate); | |||
format->setInt32("bitrate", in->format->bitrate); | |||
break; | |||
default: | |||
break; | |||
} | |||
format->setString("mime", mime); | |||
/* Handle the codec specific data */ | |||
if (in->format->extradata_size) | |||
{ | |||
sp<ABuffer> csd = new ABuffer(in->format->extradata, | |||
in->format->extradata_size); | |||
csd->meta()->setInt32("csd", true); | |||
csd->meta()->setInt64("timeUs", 0); | |||
format->setBuffer("csd-0", csd); | |||
} | |||
/* Propagate the buffer size setting of the input port to the | |||
* codec */ | |||
format->setInt32("max-input-size", in->buffer_size); | |||
LOG_TRACE("configuring: %s", format->debugString().c_str()); | |||
astatus = module->codec->configure(format, NULL, NULL, 0); | |||
if (astatus) | |||
{ | |||
LOG_ERROR("configure failed (%i)", astatus); | |||
return MMAL_EINVAL; | |||
} | |||
LOG_TRACE("starting"); | |||
astatus = module->codec->start(); | |||
if (astatus != OK) | |||
{ | |||
LOG_ERROR("failed to start codec (%i)", astatus); | |||
return MMAL_EINVAL; | |||
} | |||
LOG_TRACE("started"); | |||
return MMAL_SUCCESS; | |||
} | |||
/** Enable processing on a port */ | |||
static MMAL_STATUS_T amc_input_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb) | |||
{ | |||
MMAL_COMPONENT_T *component = port->component; | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
MMAL_STATUS_T status; | |||
status_t astatus; | |||
MMAL_PARAM_UNUSED(cb); | |||
/* Make sure the format as been committed */ | |||
status = port->priv->pf_set_format(port); | |||
if (status != MMAL_SUCCESS) | |||
{ | |||
LOG_ERROR("cannot commit port format (%i)", status); | |||
return status; | |||
} | |||
status = amc_codec_start(component); | |||
if (status != MMAL_SUCCESS) | |||
return status; | |||
astatus = module->codec->getInputBuffers(&module->input_buffers); | |||
if (astatus != OK) | |||
{ | |||
LOG_ERROR("failed to get codec input buffers (%i)", astatus); | |||
return MMAL_EINVAL; | |||
} | |||
if (module->input_buffers.size()) | |||
LOG_TRACE("%i input buffers of size %i", module->input_buffers.size(), | |||
module->input_buffers.itemAt(0)->capacity()); | |||
astatus = module->codec->getOutputBuffers(&module->output_buffers); | |||
if (astatus != OK) | |||
{ | |||
LOG_ERROR("failed to get codec output buffers (%i)", astatus); | |||
return MMAL_EINVAL; | |||
} | |||
if (module->output_buffers.size()) | |||
LOG_TRACE("%i output buffers of size %i", module->output_buffers.size(), | |||
module->output_buffers.itemAt(0)->capacity()); | |||
module->status = MMAL_SUCCESS; | |||
return MMAL_SUCCESS; | |||
} | |||
static MMAL_STATUS_T amc_output_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb) | |||
{ | |||
MMAL_PARAM_UNUSED(port); | |||
MMAL_PARAM_UNUSED(cb); | |||
return MMAL_SUCCESS; | |||
} | |||
/** Flush a port */ | |||
static MMAL_STATUS_T amc_port_flush(MMAL_PORT_T *port) | |||
{ | |||
MMAL_PORT_MODULE_T *port_module = port->priv->module; | |||
MMAL_BUFFER_HEADER_T *buffer; | |||
MMAL_COMPONENT_T *component = port->component; | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
status_t astatus; | |||
/* Flush buffers that our component is holding on to */ | |||
buffer = mmal_queue_get(port_module->queue); | |||
while(buffer) | |||
{ | |||
mmal_port_buffer_header_callback(port, buffer); | |||
buffer = mmal_queue_get(port_module->queue); | |||
} | |||
if (port_module->dequeued) | |||
port_module->dequeued->clear(); | |||
/* Flush codec itself */ | |||
if (port->type == MMAL_PORT_TYPE_INPUT && module->codec != NULL) | |||
{ | |||
astatus = module->codec->flush(); | |||
if (astatus != OK) | |||
LOG_ERROR("failed to flush codec (%i)", astatus); | |||
} | |||
return MMAL_SUCCESS; | |||
} | |||
/** Disable processing on a port */ | |||
static MMAL_STATUS_T amc_port_disable(MMAL_PORT_T *port) | |||
{ | |||
MMAL_COMPONENT_T *component = port->component; | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
status_t astatus; | |||
if (port->type == MMAL_PORT_TYPE_INPUT) | |||
{ | |||
astatus = module->codec->stop(); | |||
if (astatus != OK) | |||
LOG_ERROR("failed to stop codec (%i)", astatus); | |||
module->codec->release(); | |||
module->codec = NULL; | |||
} | |||
/* We just need to flush our internal queue */ | |||
return amc_port_flush(port); | |||
} | |||
/** Send a buffer header to a port */ | |||
static MMAL_STATUS_T amc_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) | |||
{ | |||
mmal_queue_put(port->priv->module->queue, buffer); | |||
mmal_component_action_trigger(port->component); | |||
return MMAL_SUCCESS; | |||
} | |||
/** Set format on input port */ | |||
static MMAL_STATUS_T amc_input_port_format_commit(MMAL_PORT_T *in) | |||
{ | |||
MMAL_STATUS_T status; | |||
const char *mime; | |||
if (in->is_enabled) | |||
return MMAL_EINVAL; | |||
if (!mmal_format_compare(in->format, in->priv->module->format)) | |||
return MMAL_SUCCESS; | |||
mime = encoding_to_mime(in->format->type, in->format->encoding, | |||
in->format->encoding_variant); | |||
if (!mime) | |||
{ | |||
LOG_ERROR("cannot match codec %4.4s(%4.4s) with a mime type", | |||
(char *)&in->format->encoding, (char *)&in->format->encoding_variant); | |||
return MMAL_EINVAL; | |||
} | |||
/* Note that the MediaCodec object is only created when the input | |||
* port is enabled to avoid deadlocking when we're running inside an | |||
* Android OMX component (you can't create an OMX odec instance while | |||
* you're already instantiating one) */ | |||
status = mmal_format_full_copy(in->priv->module->format, in->format); | |||
if (status != MMAL_SUCCESS) | |||
return status; | |||
/* No need to propagate anything to the output port since | |||
* we'll generate a format change event for it later on */ | |||
return status; | |||
} | |||
/** Set format on output port */ | |||
static MMAL_STATUS_T amc_output_port_format_commit(MMAL_PORT_T *out) | |||
{ | |||
/* The format of the output port needs to match the output of | |||
* MediaCodec */ | |||
if (mmal_format_compare(out->format, out->priv->module->format)) | |||
return MMAL_EINVAL; | |||
out->priv->module->needs_configuring = 0; | |||
mmal_component_action_trigger(out->component); | |||
return MMAL_SUCCESS; | |||
} | |||
/** Create an instance of a component */ | |||
static MMAL_STATUS_T mmal_component_create_android_media_codec(const char *name, MMAL_COMPONENT_T *component) | |||
{ | |||
MMAL_COMPONENT_MODULE_T *module; | |||
MMAL_STATUS_T status = MMAL_ENOMEM; | |||
const char *variant_name = name + sizeof("amc"); | |||
unsigned int variant = AMC_VARIANT_UNKNOWN; | |||
if (!strcmp(variant_name, AMC_VARIANT_AUDIO_DECODE_NAME)) | |||
variant = AMC_VARIANT_AUDIO_DECODE; | |||
if (variant == AMC_VARIANT_UNKNOWN) | |||
{ | |||
LOG_ERROR("unsupported variant %s", variant_name); | |||
return MMAL_ENOENT; | |||
} | |||
/* Allocate the context for our module */ | |||
component->priv->module = module = new MMAL_COMPONENT_MODULE_T; | |||
if (!module) | |||
return MMAL_ENOMEM; | |||
component->priv->pf_destroy = amc_component_destroy; | |||
module->status = MMAL_SUCCESS; | |||
ProcessState::self()->startThreadPool(); | |||
module->ahandler = new AmcHandler(component); | |||
module->alooper = new ALooper; | |||
module->alooper->setName("amc_looper"); | |||
module->alooper->registerHandler(module->ahandler); | |||
module->alooper->start(false); | |||
/* Allocate and initialise all the ports for this component */ | |||
component->input = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_INPUT, sizeof(MMAL_PORT_MODULE_T)); | |||
if(!component->input) | |||
goto error; | |||
component->input_num = 1; | |||
component->input[0]->priv->pf_enable = amc_input_port_enable; | |||
component->input[0]->priv->pf_disable = amc_port_disable; | |||
component->input[0]->priv->pf_flush = amc_port_flush; | |||
component->input[0]->priv->pf_send = amc_port_send; | |||
component->input[0]->priv->pf_set_format = amc_input_port_format_commit; | |||
component->input[0]->buffer_num_min = 1; | |||
component->input[0]->buffer_num_recommended = 3; | |||
component->input[0]->priv->module->queue = mmal_queue_create(); | |||
if(!component->input[0]->priv->module->queue) | |||
goto error; | |||
component->input[0]->priv->module->format = mmal_format_alloc(); | |||
if(!component->input[0]->priv->module->format) | |||
goto error; | |||
component->input[0]->priv->module->dequeued = new List<size_t>; | |||
if(!component->input[0]->priv->module->dequeued) | |||
goto error; | |||
component->output = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_OUTPUT, sizeof(MMAL_PORT_MODULE_T)); | |||
if(!component->output) | |||
goto error; | |||
component->output_num = 1; | |||
component->output[0]->priv->pf_enable = amc_output_port_enable; | |||
component->output[0]->priv->pf_disable = amc_port_disable; | |||
component->output[0]->priv->pf_flush = amc_port_flush; | |||
component->output[0]->priv->pf_send = amc_port_send; | |||
component->output[0]->priv->pf_set_format = amc_output_port_format_commit; | |||
component->output[0]->buffer_num_min = 1; | |||
component->output[0]->buffer_num_recommended = 3; | |||
component->output[0]->priv->module->queue = mmal_queue_create(); | |||
if(!component->output[0]->priv->module->queue) | |||
goto error; | |||
component->output[0]->priv->module->format = mmal_format_alloc(); | |||
if(!component->output[0]->priv->module->format) | |||
goto error; | |||
status = mmal_component_action_register(component, amc_do_processing_loop); | |||
if (status != MMAL_SUCCESS) | |||
goto error; | |||
/* Setup ports according to selected variant */ | |||
if (variant == AMC_VARIANT_AUDIO_DECODE) | |||
{ | |||
component->input[0]->format->type = MMAL_ES_TYPE_AUDIO; | |||
component->input[0]->format->encoding = MMAL_ENCODING_EAC3; | |||
component->input[0]->format->es->audio.sample_rate = 48000; | |||
component->input[0]->format->es->audio.channels = 2; | |||
component->input[0]->buffer_size_min = 4 * 1024; | |||
component->output[0]->format->type = MMAL_ES_TYPE_AUDIO; | |||
component->output[0]->format->encoding = MMAL_ENCODING_PCM_SIGNED; | |||
component->output[0]->format->es->audio.sample_rate = 48000; | |||
component->output[0]->format->es->audio.channels = 2; | |||
component->output[0]->format->es->audio.bits_per_sample = 16; | |||
component->output[0]->buffer_size_min = 32 * 1024; | |||
} | |||
/* Update our current view of the output format */ | |||
mmal_format_copy(component->output[0]->priv->module->format, | |||
component->output[0]->format); | |||
return MMAL_SUCCESS; | |||
error: | |||
amc_component_destroy(component); | |||
return status; | |||
} | |||
MMAL_CONSTRUCTOR(mmal_register_component_android_media_codec); | |||
void mmal_register_component_android_media_codec(void) | |||
{ | |||
mmal_component_supplier_register("amc", mmal_component_create_android_media_codec); | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} | |||
@@ -0,0 +1,278 @@ | |||
/* | |||
Copyright (c) 2012, Broadcom Europe Ltd | |||
All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright | |||
notice, this list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright | |||
notice, this list of conditions and the following disclaimer in the | |||
documentation and/or other materials provided with the distribution. | |||
* Neither the name of the copyright holder nor the | |||
names of its contributors may be used to endorse or promote products | |||
derived from this software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY | |||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
#include "mmal.h" | |||
#include "mmal_logging.h" | |||
#include "core/mmal_component_private.h" | |||
#include "core/mmal_port_private.h" | |||
#include <SDL/SDL.h> | |||
#define FRAME_LENGTH 2048 | |||
/* Buffering requirements */ | |||
#define INPUT_MIN_BUFFER_NUM 4 | |||
#define INPUT_RECOMMENDED_BUFFER_NUM 8 | |||
/****************************/ | |||
typedef struct MMAL_COMPONENT_MODULE_T | |||
{ | |||
MMAL_STATUS_T status; | |||
MMAL_QUEUE_T *queue; | |||
MMAL_BOOL_T audio_opened; | |||
} MMAL_COMPONENT_MODULE_T; | |||
/** Destroy a previously created component */ | |||
static MMAL_STATUS_T sdl_component_destroy(MMAL_COMPONENT_T *component) | |||
{ | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
if (module->audio_opened) | |||
SDL_CloseAudio(); | |||
SDL_QuitSubSystem(SDL_INIT_AUDIO); | |||
if(component->input_num) mmal_ports_free(component->input, 1); | |||
if(module->queue) mmal_queue_destroy(module->queue); | |||
vcos_free(module); | |||
return MMAL_SUCCESS; | |||
} | |||
static void sdl_callback( void *ctx, uint8_t *stream, int size ) | |||
{ | |||
MMAL_PORT_T *port = (MMAL_PORT_T *)ctx; | |||
MMAL_COMPONENT_T *component = port->component; | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
MMAL_BUFFER_HEADER_T *buffer; | |||
unsigned int i, bytes; | |||
while (size > 0) | |||
{ | |||
buffer = mmal_queue_get(module->queue); | |||
if (!buffer) | |||
{ | |||
LOG_ERROR("audio underrun"); | |||
return; | |||
} | |||
if (port->format->encoding == MMAL_ENCODING_PCM_SIGNED && | |||
port->format->es->audio.bits_per_sample == 16) | |||
{ | |||
bytes = buffer->length; | |||
if (bytes > (unsigned int)size) bytes = size; | |||
memcpy(stream, buffer->data + buffer->offset, bytes); | |||
buffer->offset += bytes; | |||
buffer->length -= bytes; | |||
stream += bytes; | |||
size -= bytes; | |||
} | |||
else if (port->format->es->audio.bits_per_sample == 32) | |||
{ | |||
bytes = buffer->length; | |||
if (bytes > 2 * (unsigned int)size) bytes = 2 * size; | |||
vcos_assert(!(bytes&0x3)); | |||
if (port->format->encoding == MMAL_ENCODING_PCM_FLOAT) | |||
{ | |||
float *in = (float *)(buffer->data + buffer->offset); | |||
int16_t *out = (int16_t *)stream; | |||
for (i = 0; i < bytes / 4; i++) | |||
{ | |||
if (*in >= 1.0) *out = 32767; | |||
else if (*in < -1.0) *out = -32768; | |||
else *out = *in * 32768.0; | |||
in++; out++; | |||
} | |||
} | |||
else if (port->format->encoding == MMAL_ENCODING_PCM_SIGNED) | |||
{ | |||
int32_t *in = (int32_t *)(buffer->data + buffer->offset); | |||
int16_t *out = (int16_t *)stream; | |||
for (i = 0; i < bytes / 4; i++) | |||
*out++ = (*in++) >> 16; | |||
} | |||
buffer->offset += bytes; | |||
buffer->length -= bytes; | |||
stream += bytes / 2; | |||
size -= bytes / 2; | |||
} | |||
if (buffer->length) | |||
{ | |||
/* We still have some data left for next time */ | |||
mmal_queue_put_back(module->queue, buffer); | |||
continue; | |||
} | |||
/* Handle the EOS */ | |||
if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS) | |||
mmal_event_eos_send(port); | |||
buffer->offset = 0; | |||
mmal_port_buffer_header_callback(port, buffer); | |||
} | |||
} | |||
/** Set format on a port */ | |||
static MMAL_STATUS_T sdl_port_set_format(MMAL_PORT_T *port) | |||
{ | |||
MMAL_COMPONENT_T *component = port->component; | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
SDL_AudioSpec desired, obtained; | |||
if (port->format->encoding != MMAL_ENCODING_PCM_SIGNED && | |||
port->format->encoding != MMAL_ENCODING_PCM_FLOAT && | |||
port->format->es->audio.bits_per_sample != 16 && | |||
port->format->es->audio.bits_per_sample != 32) | |||
{ | |||
LOG_ERROR("port does not support '%4.4s' at %ibps", | |||
(char *)&port->format->encoding, port->format->es->audio.bits_per_sample); | |||
return MMAL_EINVAL; | |||
} | |||
if (module->audio_opened) | |||
SDL_CloseAudio(); | |||
module->audio_opened = MMAL_FALSE; | |||
desired.freq = port->format->es->audio.sample_rate; | |||
desired.format = AUDIO_S16SYS; | |||
desired.channels = port->format->es->audio.channels; | |||
desired.callback = sdl_callback; | |||
desired.userdata = port; | |||
desired.samples = FRAME_LENGTH; | |||
/* Open the sound device. */ | |||
if (SDL_OpenAudio( &desired, &obtained ) < 0) | |||
return MMAL_ENOSYS; | |||
module->audio_opened = MMAL_TRUE; | |||
/* Now have a look at what we got. */ | |||
if (obtained.format != AUDIO_S16SYS) | |||
return MMAL_ENOSYS; | |||
port->format->es->audio.sample_rate = obtained.freq; | |||
port->format->es->audio.channels = obtained.channels; | |||
port->buffer_size_min = obtained.samples * port->format->es->audio.channels * 2; | |||
return MMAL_SUCCESS; | |||
} | |||
/** Enable processing on a port */ | |||
static MMAL_STATUS_T sdl_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb) | |||
{ | |||
MMAL_PARAM_UNUSED(port); | |||
MMAL_PARAM_UNUSED(cb); | |||
SDL_PauseAudio( 0 ); | |||
return MMAL_SUCCESS; | |||
} | |||
/** Disable processing on a port */ | |||
static MMAL_STATUS_T sdl_port_disable(MMAL_PORT_T *port) | |||
{ | |||
MMAL_COMPONENT_T *component = port->component; | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
MMAL_BUFFER_HEADER_T *buffer; | |||
SDL_PauseAudio( 1 ); | |||
while((buffer = mmal_queue_get(module->queue))) | |||
mmal_port_buffer_header_callback(port, buffer); | |||
return MMAL_SUCCESS; | |||
} | |||
static MMAL_STATUS_T sdl_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) | |||
{ | |||
MMAL_COMPONENT_T *component = port->component; | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
/* Handle event buffers */ | |||
if (buffer->cmd) | |||
{ | |||
LOG_ERROR("discarding event %i on port %p", (int)buffer->cmd, port); | |||
buffer->length = 0; | |||
mmal_port_buffer_header_callback(port, buffer); | |||
return MMAL_SUCCESS; | |||
} | |||
if (module->status != MMAL_SUCCESS) | |||
return module->status; | |||
mmal_queue_put(module->queue, buffer); | |||
return MMAL_SUCCESS; | |||
} | |||
/** Create an instance of a component */ | |||
static MMAL_STATUS_T mmal_component_create_sdl(const char *name, MMAL_COMPONENT_T *component) | |||
{ | |||
MMAL_COMPONENT_MODULE_T *module; | |||
/* Check we're the requested component */ | |||
if(strcmp(name, "sdl." MMAL_AUDIO_RENDER)) | |||
return MMAL_ENOENT; | |||
if( SDL_WasInit(SDL_INIT_AUDIO) ) | |||
return MMAL_ENXIO; | |||
/* Allocate our module context */ | |||
component->priv->module = module = vcos_calloc(1, sizeof(*module), "mmal module"); | |||
if(!module) | |||
return MMAL_ENOMEM; | |||
if(SDL_Init(SDL_INIT_AUDIO|SDL_INIT_NOPARACHUTE) < 0) | |||
return MMAL_ENXIO; | |||
/* Allocate the ports for this component */ | |||
component->input = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_INPUT, 0); | |||
if(!component->input) | |||
goto error; | |||
component->input_num = 1; | |||
module->queue = mmal_queue_create(); | |||
if(!module->queue) | |||
goto error; | |||
component->input[0]->priv->pf_set_format = sdl_port_set_format; | |||
component->input[0]->priv->pf_enable = sdl_port_enable; | |||
component->input[0]->priv->pf_disable = sdl_port_disable; | |||
component->input[0]->priv->pf_send = sdl_port_send; | |||
component->input[0]->buffer_num_min = INPUT_MIN_BUFFER_NUM; | |||
component->input[0]->buffer_num_recommended = INPUT_RECOMMENDED_BUFFER_NUM; | |||
component->priv->pf_destroy = sdl_component_destroy; | |||
return MMAL_SUCCESS; | |||
error: | |||
sdl_component_destroy(component); | |||
return MMAL_ENOMEM; | |||
} | |||
MMAL_CONSTRUCTOR(mmal_register_component_sdl_audio); | |||
void mmal_register_component_sdl_audio(void) | |||
{ | |||
mmal_component_supplier_register("sdl", mmal_component_create_sdl); | |||
} |
@@ -0,0 +1,394 @@ | |||
/* | |||
Copyright (c) 2012, Broadcom Europe Ltd | |||
All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright | |||
notice, this list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright | |||
notice, this list of conditions and the following disclaimer in the | |||
documentation and/or other materials provided with the distribution. | |||
* Neither the name of the copyright holder nor the | |||
names of its contributors may be used to endorse or promote products | |||
derived from this software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY | |||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
#include "mmal.h" | |||
#include "mmal_logging.h" | |||
#include "core/mmal_component_private.h" | |||
#include "core/mmal_port_private.h" | |||
#include <SDL/SDL.h> | |||
#define NUM_PORTS_INPUT 1 | |||
#define SDL_WIDTH 800 | |||
#define SDL_HEIGHT 600 | |||
/* Buffering requirements */ | |||
#define INPUT_MIN_BUFFER_NUM 1 | |||
#define INPUT_RECOMMENDED_BUFFER_NUM 4 | |||
/****************************/ | |||
typedef struct MMAL_COMPONENT_MODULE_T | |||
{ | |||
SDL_Overlay *sdl_overlay; | |||
SDL_Surface *sdl_surface; | |||
unsigned int width; | |||
unsigned int height; | |||
MMAL_STATUS_T status; | |||
MMAL_RECT_T display_region; | |||
MMAL_QUEUE_T *queue; | |||
SDL_Thread *thread; | |||
MMAL_BOOL_T quit; | |||
} MMAL_COMPONENT_MODULE_T; | |||
static MMAL_STATUS_T sdl_port_parameter_set(MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param) | |||
{ | |||
MMAL_STATUS_T status = MMAL_ENOSYS; | |||
MMAL_COMPONENT_T *component = port->component; | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
switch (param->id) | |||
{ | |||
case MMAL_PARAMETER_DISPLAYREGION: | |||
{ | |||
/* We only support setting the destination rectangle */ | |||
const MMAL_DISPLAYREGION_T *display = (const MMAL_DISPLAYREGION_T *)param; | |||
if (display->set & MMAL_DISPLAY_SET_DEST_RECT) | |||
module->display_region = display->dest_rect; | |||
status = MMAL_SUCCESS; | |||
} | |||
break; | |||
default: | |||
break; | |||
} | |||
return status; | |||
} | |||
/** Destroy a previously created component */ | |||
static MMAL_STATUS_T sdl_component_destroy(MMAL_COMPONENT_T *component) | |||
{ | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
SDL_Event event = {SDL_QUIT}; | |||
module->quit = MMAL_TRUE; | |||
SDL_PushEvent(&event); | |||
if(module->thread) | |||
SDL_WaitThread(module->thread, NULL); | |||
if(module->sdl_overlay) | |||
SDL_FreeYUVOverlay(module->sdl_overlay); | |||
if(module->sdl_surface) | |||
SDL_FreeSurface(module->sdl_surface); | |||
SDL_QuitSubSystem(SDL_INIT_VIDEO); | |||
if(component->input_num) mmal_ports_free(component->input, 1); | |||
if(module->queue) mmal_queue_destroy(module->queue); | |||
vcos_free(module); | |||
return MMAL_SUCCESS; | |||
} | |||
static MMAL_STATUS_T mmal_sdl_create_surface(MMAL_COMPONENT_MODULE_T *module) | |||
{ | |||
uint32_t flags; | |||
int bpp; | |||
int w = module->display_region.width; | |||
int h = module->display_region.height; | |||
flags = SDL_ANYFORMAT | SDL_HWPALETTE | SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_RESIZABLE; | |||
bpp = SDL_VideoModeOK(w, h, 16, flags); | |||
if(!bpp) | |||
{ | |||
LOG_ERROR("no SDL video mode available"); | |||
return MMAL_ENOSYS; | |||
} | |||
module->sdl_surface = SDL_SetVideoMode(w, h, bpp, flags); | |||
if(!module->sdl_surface) | |||
{ | |||
LOG_ERROR("cannot create SDL surface"); | |||
return MMAL_ENOMEM; | |||
} | |||
return MMAL_SUCCESS; | |||
} | |||
/** Set format on a port */ | |||
static MMAL_STATUS_T sdl_port_set_format(MMAL_PORT_T *port) | |||
{ | |||
MMAL_COMPONENT_T *component = port->component; | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
MMAL_STATUS_T status; | |||
if ((status=mmal_sdl_create_surface(module)) != MMAL_SUCCESS) | |||
return status; | |||
/* We only support I420 */ | |||
if (port->format->encoding != MMAL_ENCODING_I420) | |||
return MMAL_ENOSYS; | |||
/* Check if we need to re-create an overlay */ | |||
if (module->sdl_overlay && | |||
module->width == port->format->es->video.width && | |||
module->height == port->format->es->video.height) | |||
return MMAL_SUCCESS; /* Nothing to do */ | |||
if (module->sdl_overlay) | |||
SDL_FreeYUVOverlay(module->sdl_overlay); | |||
/* Create overlay */ | |||
module->sdl_overlay = | |||
SDL_CreateYUVOverlay(port->format->es->video.width, | |||
port->format->es->video.height, | |||
SDL_YV12_OVERLAY, module->sdl_surface); | |||
if (!module->sdl_overlay) | |||
{ | |||
LOG_ERROR("cannot create SDL overlay"); | |||
return MMAL_ENOSPC; | |||
} | |||
module->width = port->format->es->video.width; | |||
module->height = port->format->es->video.height; | |||
port->buffer_size_min = module->width * module->height * 3 / 2; | |||
return MMAL_SUCCESS; | |||
} | |||
/** Enable processing on a port */ | |||
static MMAL_STATUS_T sdl_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb) | |||
{ | |||
MMAL_PARAM_UNUSED(port); | |||
MMAL_PARAM_UNUSED(cb); | |||
return MMAL_SUCCESS; | |||
} | |||
/** Disable processing on a port */ | |||
static MMAL_STATUS_T sdl_port_disable(MMAL_PORT_T *port) | |||
{ | |||
MMAL_PARAM_UNUSED(port); | |||
return MMAL_SUCCESS; | |||
} | |||
/** Flush a port */ | |||
static MMAL_STATUS_T sdl_port_flush(MMAL_PORT_T *port) | |||
{ | |||
MMAL_COMPONENT_T *component = port->component; | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
MMAL_BUFFER_HEADER_T *buffer; | |||
/* Flush buffers that our component is holding on to. | |||
* If the reading thread is holding onto a buffer it will send it back ASAP as well | |||
* so no need to care about that. */ | |||
while((buffer = mmal_queue_get(module->queue))) | |||
mmal_port_buffer_header_callback(port, buffer); | |||
return MMAL_SUCCESS; | |||
} | |||
static MMAL_BOOL_T sdl_do_processing(MMAL_COMPONENT_T *component) | |||
{ | |||
MMAL_PORT_T *port = component->input[0]; | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
unsigned int width = port->format->es->video.width; | |||
unsigned int height = port->format->es->video.height; | |||
MMAL_BUFFER_HEADER_T *buffer; | |||
uint8_t *src_plane[3]; | |||
uint32_t *src_pitch; | |||
unsigned int i, line; | |||
MMAL_BOOL_T eos; | |||
SDL_Rect rect; | |||
buffer = mmal_queue_get(module->queue); | |||
if (!buffer) | |||
return 0; | |||
eos = buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS; | |||
/* Handle event buffers */ | |||
if (buffer->cmd) | |||
{ | |||
MMAL_EVENT_FORMAT_CHANGED_T *event = mmal_event_format_changed_get(buffer); | |||
if (event) | |||
{ | |||
mmal_format_copy(port->format, event->format); | |||
module->status = port->priv->pf_set_format(port); | |||
if (module->status != MMAL_SUCCESS) | |||
{ | |||
LOG_ERROR("format not set on port %p", port); | |||
if (mmal_event_error_send(port->component, module->status) != MMAL_SUCCESS) | |||
LOG_ERROR("unable to send an error event buffer"); | |||
} | |||
} | |||
else | |||
{ | |||
LOG_ERROR("discarding event %i on port %p", (int)buffer->cmd, port); | |||
} | |||
buffer->length = 0; | |||
mmal_port_buffer_header_callback(port, buffer); | |||
return 1; | |||
} | |||
if (module->status != MMAL_SUCCESS) | |||
return 1; | |||
/* Ignore empty buffers */ | |||
if (!buffer->length) | |||
goto end; | |||
// FIXME: sanity check the size of the buffer | |||
/* Blit the buffer onto the overlay. */ | |||
src_pitch = buffer->type->video.pitch; | |||
src_plane[0] = buffer->data + buffer->type->video.offset[0]; | |||
src_plane[1] = buffer->data + buffer->type->video.offset[2]; | |||
src_plane[2] = buffer->data + buffer->type->video.offset[1]; | |||
SDL_LockYUVOverlay(module->sdl_overlay); | |||
for (i=0; i<3; i++) | |||
{ | |||
uint8_t *src = src_plane[i]; | |||
uint8_t *dst = module->sdl_overlay->pixels[i]; | |||
if(i == 1) {width /= 2; height /= 2;} | |||
for(line = 0; line < height; line++) | |||
{ | |||
memcpy(dst, src, width); | |||
src += src_pitch[i]; | |||
dst += module->sdl_overlay->pitches[i]; | |||
} | |||
} | |||
SDL_UnlockYUVOverlay(module->sdl_overlay); | |||
width = port->format->es->video.width; | |||
height = port->format->es->video.height; | |||
rect.x = module->display_region.x; | |||
rect.w = module->display_region.width; | |||
height = rect.w * height / width; | |||
rect.y = module->display_region.y + (module->display_region.height - height) / 2; | |||
rect.h = height; | |||
SDL_DisplayYUVOverlay(module->sdl_overlay, &rect); | |||
end: | |||
buffer->offset = buffer->length = 0; | |||
mmal_port_buffer_header_callback(port, buffer); | |||
/* Generate EOS events */ | |||
if (eos) | |||
mmal_event_eos_send(port); | |||
return 1; | |||
} | |||
/*****************************************************************************/ | |||
static void sdl_do_processing_loop(MMAL_COMPONENT_T *component) | |||
{ | |||
while (sdl_do_processing(component)); | |||
} | |||
/** Buffer sending */ | |||
static MMAL_STATUS_T sdl_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) | |||
{ | |||
MMAL_COMPONENT_T *component = port->component; | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
mmal_queue_put(module->queue, buffer); | |||
mmal_component_action_trigger(port->component); | |||
return MMAL_SUCCESS; | |||
} | |||
/** SDL event thread */ | |||
static int sdl_event_thread(void *arg) | |||
{ | |||
MMAL_COMPONENT_T *component = (MMAL_COMPONENT_T *)arg; | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
SDL_Event event; | |||
while (SDL_WaitEvent(&event)) | |||
{ | |||
switch (event.type) | |||
{ | |||
case SDL_QUIT: | |||
if (!module->quit) | |||
mmal_event_error_send(component, MMAL_SUCCESS); | |||
return 0; | |||
default: | |||
break; | |||
} | |||
} | |||
return 0; | |||
} | |||
/** Create an instance of a component */ | |||
static MMAL_STATUS_T mmal_component_create_sdl(const char *name, MMAL_COMPONENT_T *component) | |||
{ | |||
MMAL_COMPONENT_MODULE_T *module; | |||
MMAL_STATUS_T status = MMAL_ENOMEM; | |||
/* Check we're the requested component */ | |||
if(strcmp(name, "sdl." MMAL_VIDEO_RENDER)) | |||
return MMAL_ENOENT; | |||
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_EVENTTHREAD|SDL_INIT_NOPARACHUTE) < 0) | |||
return MMAL_ENXIO; | |||
/* Allocate our module context */ | |||
component->priv->module = module = vcos_calloc(1, sizeof(*module), "mmal module"); | |||
if(!module) return MMAL_ENOMEM; | |||
module->queue = mmal_queue_create(); | |||
if(!module->queue) goto error; | |||
/* Allocate the ports for this component */ | |||
component->input = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_INPUT, 0); | |||
if(!component->input) goto error; | |||
component->input_num = 1; | |||
module->display_region.width = SDL_WIDTH; | |||
module->display_region.height = SDL_HEIGHT; | |||
/************/ | |||
component->input[0]->priv->pf_set_format = sdl_port_set_format; | |||
component->input[0]->priv->pf_enable = sdl_port_enable; | |||
component->input[0]->priv->pf_disable = sdl_port_disable; | |||
component->input[0]->priv->pf_flush = sdl_port_flush; | |||
component->input[0]->priv->pf_send = sdl_port_send; | |||
component->input[0]->priv->pf_parameter_set = sdl_port_parameter_set; | |||
component->input[0]->buffer_num_min = INPUT_MIN_BUFFER_NUM; | |||
component->input[0]->buffer_num_recommended = INPUT_RECOMMENDED_BUFFER_NUM; | |||
component->priv->pf_destroy = sdl_component_destroy; | |||
/* Create a thread to monitor SDL events */ | |||
module->thread = SDL_CreateThread(sdl_event_thread, component); | |||
status = mmal_component_action_register(component, sdl_do_processing_loop); | |||
if (status != MMAL_SUCCESS) | |||
goto error; | |||
return MMAL_SUCCESS; | |||
error: | |||
sdl_component_destroy(component); | |||
return status; | |||
} | |||
MMAL_CONSTRUCTOR(mmal_register_component_sdl); | |||
void mmal_register_component_sdl(void) | |||
{ | |||
mmal_component_supplier_register("sdl", mmal_component_create_sdl); | |||
} |
@@ -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); | |||
} |
@@ -0,0 +1,345 @@ | |||
/* | |||
Copyright (c) 2012, Broadcom Europe Ltd | |||
All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright | |||
notice, this list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright | |||
notice, this list of conditions and the following disclaimer in the | |||
documentation and/or other materials provided with the distribution. | |||
* Neither the name of the copyright holder nor the | |||
names of its contributors may be used to endorse or promote products | |||
derived from this software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY | |||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
#include "mmal.h" | |||
#include "core/mmal_component_private.h" | |||
#include "core/mmal_port_private.h" | |||
#include "mmal_logging.h" | |||
#define SPLITTER_OUTPUT_PORTS_NUM 4 /* 4 should do for now */ | |||
/*****************************************************************************/ | |||
typedef struct MMAL_COMPONENT_MODULE_T | |||
{ | |||
uint32_t enabled_flags; /**< Flags indicating which output port is enabled */ | |||
uint32_t sent_flags; /**< Flags indicating which output port we've already sent data to */ | |||
MMAL_BOOL_T error; /**< Error state */ | |||
} MMAL_COMPONENT_MODULE_T; | |||
typedef struct MMAL_PORT_MODULE_T | |||
{ | |||
MMAL_QUEUE_T *queue; /**< queue for the buffers sent to the ports */ | |||
} MMAL_PORT_MODULE_T; | |||
/*****************************************************************************/ | |||
/** Destroy a previously created component */ | |||
static MMAL_STATUS_T splitter_component_destroy(MMAL_COMPONENT_T *component) | |||
{ | |||
unsigned int i; | |||
for(i = 0; i < component->input_num; i++) | |||
if(component->input[i]->priv->module->queue) | |||
mmal_queue_destroy(component->input[i]->priv->module->queue); | |||
if(component->input_num) | |||
mmal_ports_free(component->input, component->input_num); | |||
for(i = 0; i < component->output_num; i++) | |||
if(component->output[i]->priv->module->queue) | |||
mmal_queue_destroy(component->output[i]->priv->module->queue); | |||
if(component->output_num) | |||
mmal_ports_free(component->output, component->output_num); | |||
vcos_free(component->priv->module); | |||
return MMAL_SUCCESS; | |||
} | |||
/** Enable processing on a port */ | |||
static MMAL_STATUS_T splitter_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb) | |||
{ | |||
#if 0 | |||
MMAL_COMPONENT_T *component = port->component; | |||
uint32_t buffer_num, buffer_size; | |||
unsigned int i; | |||
/* Find the max and apply that to all ports */ | |||
buffer_num = component->input[0]->buffer_num; | |||
buffer_size = component->input[0]->buffer_size; | |||
for (i = 0; i < component->output_num; i++) | |||
{ | |||
buffer_num = MMAL_MAX(buffer_num, component->output[i]->buffer_num); | |||
buffer_size = MMAL_MAX(buffer_num, component->output[i]->buffer_size); | |||
} | |||
component->input[0]->buffer_num = buffer_num; | |||
component->input[0]->buffer_size = buffer_size; | |||
for (i = 0; i < component->output_num; i++) | |||
{ | |||
component->output[i]->buffer_num = buffer_num; | |||
component->output[i]->buffer_size = buffer_num; | |||
} | |||
#endif | |||
MMAL_PARAM_UNUSED(cb); | |||
if (port->buffer_size) | |||
if (port->type == MMAL_PORT_TYPE_OUTPUT) | |||
port->component->priv->module->enabled_flags |= (1<<port->index); | |||
return MMAL_SUCCESS; | |||
} | |||
/** Flush a port */ | |||
static MMAL_STATUS_T splitter_port_flush(MMAL_PORT_T *port) | |||
{ | |||
MMAL_PORT_MODULE_T *port_module = port->priv->module; | |||
MMAL_BUFFER_HEADER_T *buffer; | |||
/* Flush buffers that our component is holding on to */ | |||
buffer = mmal_queue_get(port_module->queue); | |||
while(buffer) | |||
{ | |||
mmal_port_buffer_header_callback(port, buffer); | |||
buffer = mmal_queue_get(port_module->queue); | |||
} | |||
if (port->type == MMAL_PORT_TYPE_INPUT) | |||
port->component->priv->module->sent_flags = 0; | |||
return MMAL_SUCCESS; | |||
} | |||
/** Disable processing on a port */ | |||
static MMAL_STATUS_T splitter_port_disable(MMAL_PORT_T *port) | |||
{ | |||
if (port->type == MMAL_PORT_TYPE_OUTPUT) | |||
port->component->priv->module->enabled_flags &= ~(1<<port->index); | |||
/* We just need to flush our internal queue */ | |||
return splitter_port_flush(port); | |||
} | |||
/** Send a buffer header to a port */ | |||
static MMAL_STATUS_T splitter_send_output(MMAL_BUFFER_HEADER_T *buffer, MMAL_PORT_T *out_port) | |||
{ | |||
MMAL_BUFFER_HEADER_T *out; | |||
MMAL_STATUS_T status; | |||
/* Get a buffer header from output port */ | |||
out = mmal_queue_get(out_port->priv->module->queue); | |||
if (!out) | |||
return MMAL_EAGAIN; | |||
/* Copy our input buffer header */ | |||
status = mmal_buffer_header_replicate(out, buffer); | |||
if (status != MMAL_SUCCESS) | |||
goto error; | |||
/* Send buffer back */ | |||
mmal_port_buffer_header_callback(out_port, out); | |||
return MMAL_SUCCESS; | |||
error: | |||
mmal_queue_put_back(out_port->priv->module->queue, out); | |||
return status; | |||
} | |||
/** Send a buffer header to a port */ | |||
static MMAL_STATUS_T splitter_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) | |||
{ | |||
MMAL_COMPONENT_T *component = port->component; | |||
MMAL_COMPONENT_MODULE_T *module = component->priv->module; | |||
MMAL_PORT_T *in_port, *out_port; | |||
MMAL_BUFFER_HEADER_T *in; | |||
MMAL_STATUS_T status; | |||
unsigned int i; | |||
mmal_queue_put(port->priv->module->queue, buffer); | |||
if (module->error) | |||
return MMAL_SUCCESS; /* Just do nothing */ | |||
/* Get input buffer header */ | |||
in_port = component->input[0]; | |||
in = mmal_queue_get(in_port->priv->module->queue); | |||
if (!in) | |||
return MMAL_SUCCESS; /* Nothing to do */ | |||
for (i = 0; i < component->output_num; i++) | |||
{ | |||
out_port = component->output[i]; | |||
status = splitter_send_output(in, out_port); | |||
if (status != MMAL_SUCCESS && status != MMAL_EAGAIN) | |||
goto error; | |||
if (status == MMAL_SUCCESS) | |||
module->sent_flags |= (1<<i); | |||
} | |||
/* Check if we're done with the input buffer */ | |||
if ((module->sent_flags & module->enabled_flags) == module->enabled_flags) | |||
{ | |||
in->length = 0; /* Consume the input buffer */ | |||
mmal_port_buffer_header_callback(in_port, in); | |||
module->sent_flags = 0; | |||
return MMAL_SUCCESS; | |||
} | |||
/* We're not done yet so put the buffer back in the queue */ | |||
mmal_queue_put(in_port->priv->module->queue, in); | |||
return MMAL_SUCCESS; | |||
error: | |||
mmal_queue_put(in_port->priv->module->queue, in); | |||
status = mmal_event_error_send(port->component, status); | |||
if (status != MMAL_SUCCESS) | |||
{ | |||
LOG_ERROR("unable to send an error event buffer (%i)", (int)status); | |||
return MMAL_SUCCESS; | |||
} | |||
module->error = 1; | |||
return MMAL_SUCCESS; | |||
} | |||
/** Set format on a port */ | |||
static MMAL_STATUS_T splitter_port_format_commit(MMAL_PORT_T *port) | |||
{ | |||
MMAL_COMPONENT_T *component = port->component; | |||
MMAL_STATUS_T status; | |||
unsigned int i; | |||
/* Sanity check */ | |||
if (port->type == MMAL_PORT_TYPE_OUTPUT) | |||
{ | |||
LOG_ERROR("output port is read-only"); | |||
return MMAL_EINVAL; | |||
} | |||
/* Commit the format on all output ports */ | |||
for (i = 0; i < component->output_num; i++) | |||
{ | |||
status = mmal_format_full_copy(component->output[i]->format, port->format); | |||
if (status != MMAL_SUCCESS) | |||
return status; | |||
} | |||
return MMAL_SUCCESS; | |||
} | |||
static MMAL_STATUS_T splitter_port_parameter_set(MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param) | |||
{ | |||
MMAL_COMPONENT_T *component = port->component; | |||
unsigned int i; | |||
switch (param->id) | |||
{ | |||
case MMAL_PARAMETER_BUFFER_REQUIREMENTS: | |||
{ | |||
/* Propagate the requirements to all the ports */ | |||
const MMAL_PARAMETER_BUFFER_REQUIREMENTS_T *req = (const MMAL_PARAMETER_BUFFER_REQUIREMENTS_T *)param; | |||
uint32_t buffer_num_min = MMAL_MAX(port->buffer_num_min, req->buffer_num_min); | |||
uint32_t buffer_num_recommended = MMAL_MAX(port->buffer_num_recommended, req->buffer_num_recommended); | |||
uint32_t buffer_size_min = MMAL_MAX(port->buffer_size_min, req->buffer_size_min); | |||
uint32_t buffer_size_recommended = MMAL_MAX(port->buffer_size_recommended, req->buffer_size_recommended); | |||
component->input[0]->buffer_num_min = buffer_num_min; | |||
component->input[0]->buffer_num_recommended = buffer_num_recommended; | |||
component->input[0]->buffer_size_min = buffer_size_min; | |||
component->input[0]->buffer_size_recommended = buffer_size_recommended; | |||
for (i = 0; i < component->output_num; i++) | |||
{ | |||
component->output[i]->buffer_num_min = buffer_num_min; | |||
component->output[i]->buffer_num_recommended = buffer_num_recommended; | |||
component->output[i]->buffer_size_min = buffer_size_min; | |||
component->output[i]->buffer_size_recommended = buffer_size_recommended; | |||
} | |||
} | |||
return MMAL_SUCCESS; | |||
default: | |||
return MMAL_ENOSYS; | |||
} | |||
} | |||
/** Create an instance of a component */ | |||
static MMAL_STATUS_T mmal_component_create_splitter(const char *name, MMAL_COMPONENT_T *component) | |||
{ | |||
MMAL_COMPONENT_MODULE_T *module; | |||
MMAL_STATUS_T status = MMAL_ENOMEM; | |||
unsigned int i; | |||
MMAL_PARAM_UNUSED(name); | |||
/* Allocate the context for our module */ | |||
component->priv->module = module = vcos_malloc(sizeof(*module), "mmal module"); | |||
if (!module) | |||
return MMAL_ENOMEM; | |||
memset(module, 0, sizeof(*module)); | |||
component->priv->pf_destroy = splitter_component_destroy; | |||
/* Allocate and initialise all the ports for this component */ | |||
component->input = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_INPUT, sizeof(MMAL_PORT_MODULE_T)); | |||
if(!component->input) | |||
goto error; | |||
component->input_num = 1; | |||
component->input[0]->priv->pf_enable = splitter_port_enable; | |||
component->input[0]->priv->pf_disable = splitter_port_disable; | |||
component->input[0]->priv->pf_flush = splitter_port_flush; | |||
component->input[0]->priv->pf_send = splitter_port_send; | |||
component->input[0]->priv->pf_set_format = splitter_port_format_commit; | |||
component->input[0]->priv->pf_parameter_set = splitter_port_parameter_set; | |||
component->input[0]->buffer_num_min = 1; | |||
component->input[0]->buffer_num_recommended = 0; | |||
component->input[0]->priv->module->queue = mmal_queue_create(); | |||
if(!component->input[0]->priv->module->queue) | |||
goto error; | |||
component->output = mmal_ports_alloc(component, SPLITTER_OUTPUT_PORTS_NUM, | |||
MMAL_PORT_TYPE_OUTPUT, sizeof(MMAL_PORT_MODULE_T)); | |||
if(!component->output) | |||
goto error; | |||
component->output_num = SPLITTER_OUTPUT_PORTS_NUM; | |||
for(i = 0; i < component->output_num; i++) | |||
{ | |||
component->output[i]->priv->pf_enable = splitter_port_enable; | |||
component->output[i]->priv->pf_disable = splitter_port_disable; | |||
component->output[i]->priv->pf_flush = splitter_port_flush; | |||
component->output[i]->priv->pf_send = splitter_port_send; | |||
component->output[i]->priv->pf_set_format = splitter_port_format_commit; | |||
component->output[i]->priv->pf_parameter_set = splitter_port_parameter_set; | |||
component->output[i]->buffer_num_min = 1; | |||
component->output[i]->buffer_num_recommended = 0; | |||
component->output[i]->capabilities = MMAL_PORT_CAPABILITY_PASSTHROUGH; | |||
component->output[i]->priv->module->queue = mmal_queue_create(); | |||
if(!component->output[i]->priv->module->queue) | |||
goto error; | |||
} | |||
return MMAL_SUCCESS; | |||
error: | |||
splitter_component_destroy(component); | |||
return status; | |||
} | |||
MMAL_CONSTRUCTOR(mmal_register_component_splitter); | |||
void mmal_register_component_splitter(void) | |||
{ | |||
mmal_component_supplier_register("splitter", mmal_component_create_splitter); | |||
} |
@@ -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 | |||
) |
@@ -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; | |||
} |
@@ -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 */ |
@@ -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; | |||
} |
@@ -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 */ |
@@ -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); | |||
} | |||
} |
@@ -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 */ |
@@ -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 */ | |||
@@ -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; | |||
} |
@@ -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 */ |
@@ -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; | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
@@ -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 */ |
@@ -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); | |||
} |
@@ -0,0 +1,390 @@ | |||
/* | |||
Copyright (c) 2012, Broadcom Europe Ltd | |||
All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright | |||
notice, this list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright | |||
notice, this list of conditions and the following disclaimer in the | |||
documentation and/or other materials provided with the distribution. | |||
* Neither the name of the copyright holder nor the | |||
names of its contributors may be used to endorse or promote products | |||
derived from this software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY | |||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
/** \file | |||
* Multi-Media Abstraction Layer API | |||
*/ | |||
#ifndef MMAL_H | |||
#define MMAL_H | |||
/** | |||
* | |||
* \mainpage Multi-Media Abstraction Layer (MMAL). Draft Version 0.1. | |||
* | |||
* \par Contents | |||
* - \ref intro_sec | |||
* - \ref features | |||
* - \ref concepts | |||
* - \ref comp | |||
* - \ref create | |||
* - \ref port | |||
* - \ref buf | |||
* - \ref metadata | |||
* - \ref queue | |||
* - \ref pool | |||
* - \ref param | |||
* - \ref events | |||
* - \ref version | |||
* - \ref example | |||
* | |||
* \section intro_sec Introduction | |||
* | |||
* MMAL (Multi-Media Abstraction Layer) is a framework which is used to provide a host-side, | |||
* simple and relatively low-level interface to multimedia components running on VideoCore. | |||
* It also provides a component interface so that new components can be easily created and | |||
* integrated into the framework. | |||
* | |||
* There is no requirement that all the components be running on VideoCore as MMAL doesn't | |||
* put any restriction on where components live. The current implementation for instance | |||
* provides some components which can be run on both host-side or VideoCore (e.g. the splitter | |||
* component). | |||
* | |||
* \section features Features | |||
* | |||
* The MMAL API has been designed to support all the following features: | |||
* - Sufficiently generic to support different kinds of multimedia component. | |||
* - Simple to use from client side (mostly synchronous except where it matters). | |||
* - Straightforward API for designing components (e.g. avoids multiple data paths, as found in RIL). | |||
* - Allows for fully-optimised implementation of components (e.g. zero-copy buffer passing). | |||
* - Portability (API is self-contained). | |||
* - Supports multiple instances (e.g. of VideoCore). | |||
* - Extensible without breaking source or binary backward compatibility. | |||
* | |||
* \section concepts API concepts | |||
* | |||
* The MMAL API is based on the concept of components, ports and buffer headers. | |||
* Clients create MMAL components which expose ports for each individual | |||
* elementary stream of data they support (e.g. audio/video). Components expose | |||
* input ports to receive data from the client, and expose output ports | |||
* to return data to the client. | |||
* | |||
* Data sent to or received from the component needs to be attached to a buffer header. | |||
* Buffer headers are necessary because they contain buffer specific ancillary data which is | |||
* necessary for the component and client to do their processing (e.g timestamps). | |||
* | |||
* \section comp Components | |||
* | |||
* MMAL lets clients create multi-media components (video encoders, | |||
* video decoders, camera, and so-on) using a common API. Clients exchange | |||
* data with components using buffer headers. A buffer header | |||
* has a pointer to the payload data and optional metadata. | |||
* Buffer headers are sent to and received from ports that are provided by components. | |||
* | |||
* A typical decoder component would have a single input port and a | |||
* single output port, but the same architecture could also be used | |||
* for components with different layouts (e.g. a camera with a | |||
* capture and preview port, or a debugging component with just an input port). | |||
* | |||
* \subsection create Component Creation | |||
* | |||
* Each component is identified by a unique name. To create a specific component | |||
* the client needs to call \ref mmal_component_create with the desired component's | |||
* name as an argument. | |||
* This call will return a context (\ref MMAL_COMPONENT_T) to the component. This | |||
* context will expose the input and output ports (\ref MMAL_PORT_T) supported | |||
* by this specific component. | |||
* | |||
* \note All VideoCore components have a name starting with the "vc." prefix (this prefix | |||
* is used to distinguish when a creation request needs to be forwarded to VideoCore). | |||
* | |||
* \section port Component Ports | |||
* | |||
* A port (\ref MMAL_PORT_T) is the entity which exposes an elementary stream | |||
* (\ref MMAL_ES_FORMAT_T) on a component. It is also the entity to which buffer headers | |||
* (\ref MMAL_BUFFER_HEADER_T) are sent or from which they are received. | |||
* | |||
* Clients do not need to create ports. They are created automatically by | |||
* the component when this one is created but the format of a port might need to | |||
* be set by the client depending on the type of component the client is using. | |||
* | |||
* For example, for a video decoding component, one input port and one output port | |||
* will be available. The format of the input port must be set by the | |||
* client (using \ref mmal_port_format_commit) while the format of the output port | |||
* will be automatically set by the component once the component has enough information | |||
* to find out what its format should be. | |||
* | |||
* If the input port format contains enough information for the component to determine | |||
* the format of the output port straight away, then the output port will be set to the proper | |||
* format when \ref mmal_port_format_commit returns. Otherwise the output format will be set to | |||
* \ref MMAL_ENCODING_UNKNOWN until the component is fed enough data to determine the format | |||
* of the output port. | |||
* When this happens, the client will receive an event on the output port, signalling | |||
* that its format has changed. | |||
* | |||
* \section buf Buffer Headers | |||
* | |||
* Buffer headers (\ref MMAL_BUFFER_HEADER_T) are used to exchange data with components. | |||
* They do not contain the data directly but instead contain a pointer to the data being | |||
* transferred. | |||
* | |||
* Separating the buffer headers from the payload means that the memory for the data can | |||
* be allocated outside of MMAL (e.g. if it is supplied by an external library) while still | |||
* providing a consistent way to exchange data between clients and components. | |||
* | |||
* Buffer headers are allocated from pools and are reference counted. The refcount | |||
* will drop when \ref mmal_buffer_header_release is called and the buffer header | |||
* will be recycled to its pool when it reaches zero. | |||
* The client can be notified when the buffer header is recycled so that it can recycle the | |||
* associated payload memory as well. | |||
* | |||
* A pool of buffer headers should be created after committing the format of the port. When | |||
* the format is changed, the minimum and recommended size and number of buffers may change. | |||
* | |||
* \note The current number of buffers and their size (\ref MMAL_PORT_T::buffer_num and \ref | |||
* MMAL_PORT_T::buffer_size) are not modified by MMAL, and must be updated by the client as | |||
* required after changes to a port's format. | |||
* | |||
* \subsection metadata Buffer Metadata | |||
* | |||
* The API provides a way for clients or components to associate metadata with buffer headers. | |||
* A camera component could for example store information like exposure time or focal length | |||
* as metadata within the buffer header containing the frame just captured. | |||
* \note This area needs more work | |||
* | |||
* \subsection queue Queues of Buffer Headers | |||
* | |||
* Queues (\ref MMAL_QUEUE_T) are a facility that allows thread-safe processing of buffer headers | |||
* from the client. Callbacks triggered by a MMAL component when it sends a buffer header to the | |||
* client can simply put the buffer in a queue and let the main processing thread of the client | |||
* get its data from the queue. | |||
* | |||
* \subsection pool Pools of Buffer Headers | |||
* | |||
* Pools (\ref MMAL_POOL_T) let clients allocate a fixed number of buffer headers, and | |||
* a queue (\ref MMAL_QUEUE_T). They are used for buffer header allocation. | |||
* Optionally a pool can also allocate the payload memory for the client. | |||
* | |||
* Pools can also be resized after creation, for example, if the port format is changed leading | |||
* to a new number or size of buffers being required. | |||
* | |||
* \section param Port Parameters | |||
* | |||
* Components support setting and getting component specific parameters using | |||
* \ref mmal_port_parameter_set and \ref mmal_port_parameter_get. Parameters | |||
* are identified using an integer index; parameter data is binary. See the \ref MMAL_PARAMETER_IDS | |||
* "Pre-defined MMAL parameter IDs" page for more information on the pre-defined parameters. | |||
* | |||
* \section events Port Events | |||
* | |||
* Components can generate events on their ports. Events are sent to clients | |||
* as buffer headers and thus when the client receives a buffer header on one | |||
* of the component's port it should check if the buffer header is an event | |||
* and in which case process it and then release it (\ref mmal_buffer_header_release). | |||
* The reason for transmitting events in-band with the actual data is that it | |||
* is often very valuable to know exactly when the event happens relative to the | |||
* the actual data (e.g. with a focus event, from which video frame are we in focus).\n | |||
* Buffer headers used to transmit events are allocated internally by the framework | |||
* so it is important to release the buffer headers with \ref mmal_buffer_header_release | |||
* so the buffer headers make it back to their actual owner. | |||
* | |||
* Event buffer headers are allocated when the component is created, based on the | |||
* minimum number and size of control port buffers set by the component. Component | |||
* wide events (not port specific) are sent to the control port callback when that | |||
* port is enabled. Port events are sent to the port callback, the same as data | |||
* buffers, but the 'cmd' field is non-zero. | |||
* | |||
* \section version Versioning | |||
* | |||
* The API requires that the MMAL core be the same or more recent version | |||
* as the components and clients. Clients and components can be older and | |||
* the API will still work both at compile-time and run-time. | |||
* | |||
* \section example Example Code | |||
* | |||
* The following code is a simple example on how to do video decoding using MMAL. Note that | |||
* the code is intended to be clear and illustrate how to use MMAL at its most fundamental | |||
* level, not necessarily the most efficient way to achieve the same result. Use of opaque | |||
* images, tunneling and zero-copy inter-processor buffers can all improve the performance | |||
* or reduce the load. | |||
* | |||
* The \ref MmalConnectionUtility "Port Connection Utility" functions can also be used to | |||
* replace much of the common "boilerplate" code, especially when a pipeline of several | |||
* components needs to be processed. | |||
* | |||
* \code | |||
* #include <mmal.h> | |||
* ... | |||
* static void input_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) | |||
* { | |||
* // The decoder is done with the data, just recycle the buffer header into its pool | |||
* mmal_buffer_header_release(buffer); | |||
* } | |||
* static void output_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) | |||
* { | |||
* MMAL_QUEUE_T *queue = (MMAL_QUEUE_T *)port->userdata; | |||
* mmal_queue_put(queue, buffer); // Queue the decoded video frame | |||
* } | |||
* ... | |||
* | |||
* MMAL_COMPONENT_T *decoder = 0; | |||
* MMAL_STATUS_T status; | |||
* | |||
* // Create the video decoder component on VideoCore | |||
* status = mmal_component_create("vc.ril.video_decoder", &decoder); | |||
* ABORT_IF_ERROR(status); | |||
* | |||
* // Set format of video decoder input port | |||
* MMAL_ES_FORMAT_T *format_in = decoder->input[0]->format; | |||
* format_in->type = MMAL_ES_TYPE_VIDEO; | |||
* format_in->encoding = MMAL_ENCODING_H264; | |||
* format_in->es->video.width = 1280; | |||
* format_in->es->video.height = 720; | |||
* format_in->es->video.frame_rate.num = 30; | |||
* format_in->es->video.frame_rate.den = 1; | |||
* format_in->es->video.par.num = 1; | |||
* format_in->es->video.par.den = 1; | |||
* format_in->flags = MMAL_ES_FORMAT_FLAG_FRAMED; | |||
* status = mmal_format_extradata_alloc(format_in, YOUR_H264_CODEC_HEADER_BYTES_SIZE); | |||
* ABORT_IF_ERROR(status); | |||
* format_in->extradata_size = YOUR_H264_CODEC_HEADER_BYTES_SIZE; | |||
* memcpy(format_in->extradata, YOUR_H264_CODEC_HEADER_BYTES, format_in->extradata_size); | |||
* | |||
* status = mmal_port_format_commit(decoder->input[0]); | |||
* ABORT_IF_ERROR(status); | |||
* | |||
* // Once the call to mmal_port_format_commit() on the input port returns, the decoder will | |||
* // have set the format of the output port. | |||
* // If the decoder still doesn t have enough information to determine the format of the | |||
* // output port, the encoding will be set to unknown. As soon as the decoder receives | |||
* // enough stream data to determine the format of the output port it will send an event | |||
* // to the client to signal that the format of the port has changed. | |||
* // However, for the sake of simplicity this example assumes that the decoder was given | |||
* // all the necessary information right at the start (i.e. video format and codec header bytes) | |||
* MMAL_FORMAT_T *format_out = decoder->output[0]->format; | |||
* if (format_out->encoding == MMAL_ENCODING_UNKNOWN) | |||
* ABORT(); | |||
* | |||
* // Now we know the format of both ports and the requirements of the decoder, we can create | |||
* // our buffer headers and their associated memory buffers. We use the buffer pool API for this. | |||
* decoder->input[0]->buffer_num = decoder->input[0]->buffer_num_min; | |||
* decoder->input[0]->buffer_size = decoder->input[0]->buffer_size_min; | |||
* MMAL_POOL_T *pool_in = mmal_pool_create(decoder->input[0]->buffer_num, | |||
* decoder->input[0]->buffer_size); | |||
* decoder->output[0]->buffer_num = decoder->output[0]->buffer_num_min; | |||
* decoder->output[0]->buffer_size = decoder->output[0]->buffer_size_min; | |||
* MMAL_POOL_T *pool_out = mmal_pool_create(decoder->output[0]->buffer_num, | |||
* decoder->output[0]->buffer_size); | |||
* | |||
* // Create a queue to store our decoded video frames. The callback we will get when | |||
* // a frame has been decoded will put the frame into this queue. | |||
* MMAL_QUEUE_T *queue_decoded_frames = mmal_queue_create(); | |||
* decoder->output[0]->userdata = (void)queue_decoded_frames; | |||
* | |||
* // Enable all the input port and the output port. | |||
* // The callback specified here is the function which will be called when the buffer header | |||
* // we sent to the component has been processed. | |||
* status = mmal_port_enable(decoder->input[0], input_callback); | |||
* ABORT_IF_ERROR(status); | |||
* status = mmal_port_enable(decoder->output[0], output_callback); | |||
* ABORT_IF_ERROR(status); | |||
* | |||
* // Enable the component. Components will only process data when they are enabled. | |||
* status = mmal_component_enable(decoder); | |||
* ABORT_IF_ERROR(status); | |||
* | |||
* // Data processing loop | |||
* while (1) | |||
* { | |||
* MMAL_BUFFER_HEADER_T *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 */ |
@@ -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 */ |
@@ -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 <cassert> | |||
/** \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 */ |
@@ -0,0 +1,83 @@ | |||
/* | |||
Copyright (c) 2012, Broadcom Europe Ltd | |||
All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright | |||
notice, this list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright | |||
notice, this list of conditions and the following disclaimer in the | |||
documentation and/or other materials provided with the distribution. | |||
* Neither the name of the copyright holder nor the | |||
names of its contributors may be used to endorse or promote products | |||
derived from this software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY | |||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
/** \file mmal_common.h | |||
* Multi-Media Abstraction Layer - Common definitions | |||
*/ | |||
#ifndef MMAL_COMMON_H | |||
#define MMAL_COMMON_H | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <stddef.h> | |||
#include <assert.h> | |||
#include <vcos.h> | |||
/* C99 64bits integers */ | |||
#ifndef INT64_C | |||
# define INT64_C(value) value##LL | |||
# define UINT64_C(value) value##ULL | |||
#endif | |||
#define MMAL_TSRING(s) #s | |||
#define MMAL_TO_STRING(s) MMAL_TSRING(s) | |||
#define MMAL_COUNTOF(x) (sizeof((x))/sizeof((x)[0])) | |||
#define MMAL_MIN(a,b) ((a)<(b)?(a):(b)) | |||
#define MMAL_MAX(a,b) ((a)<(b)?(b):(a)) | |||
/* FIXME: should be different for big endian */ | |||
#define MMAL_FOURCC(a,b,c,d) ((a) | (b << 8) | (c << 16) | (d << 24)) | |||
#define MMAL_PARAM_UNUSED(a) (void)(a) | |||
#define MMAL_MAGIC MMAL_FOURCC('m','m','a','l') | |||
typedef int32_t MMAL_BOOL_T; | |||
#define MMAL_FALSE 0 | |||
#define MMAL_TRUE 1 | |||
typedef struct MMAL_CORE_STATISTICS_T | |||
{ | |||
uint32_t buffer_count; /**< Total buffer count on this port */ | |||
uint32_t first_buffer_time; /**< Time (us) of first buffer seen on this port */ | |||
uint32_t last_buffer_time; /**< Time (us) of most recently buffer on this port */ | |||
uint32_t max_delay; /**< Max delay (us) between buffers, ignoring first few frames */ | |||
} MMAL_CORE_STATISTICS_T; | |||
/** Statistics collected by the core on all ports, if enabled in the build. | |||
*/ | |||
typedef struct MMAL_CORE_PORT_STATISTICS_T | |||
{ | |||
MMAL_CORE_STATISTICS_T rx; | |||
MMAL_CORE_STATISTICS_T tx; | |||
} MMAL_CORE_PORT_STATISTICS_T; | |||
/** Unsigned 16.16 fixed point value, also known as Q16.16 */ | |||
typedef uint32_t MMAL_FIXED_16_16_T; | |||
#endif /* MMAL_COMMON_H */ |
@@ -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 */ |
@@ -0,0 +1,224 @@ | |||
/* | |||
Copyright (c) 2012, Broadcom Europe Ltd | |||
All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright | |||
notice, this list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright | |||
notice, this list of conditions and the following disclaimer in the | |||
documentation and/or other materials provided with the distribution. | |||
* Neither the name of the copyright holder nor the | |||
names of its contributors may be used to endorse or promote products | |||
derived from this software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY | |||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
(INCLUDING 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 | |||
/* @} */ | |||
/** 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 */ |
@@ -0,0 +1,87 @@ | |||
/* | |||
Copyright (c) 2012, Broadcom Europe Ltd | |||
All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright | |||
notice, this list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright | |||
notice, this list of conditions and the following disclaimer in the | |||
documentation and/or other materials provided with the distribution. | |||
* Neither the name of the copyright holder nor the | |||
names of its contributors may be used to endorse or promote products | |||
derived from this software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY | |||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
#ifndef 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" | |||
#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" | |||
#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" | |||
#endif | |||
/** @} */ | |||
#endif /* MMAL_DEFAULT_COMPONENTS_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 */ |
@@ -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 */ |
@@ -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 */ |
@@ -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 */ |
@@ -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 */ |
@@ -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 */ |
@@ -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 */ | |||
@@ -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 */ |
@@ -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 */ |
@@ -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 */ | |||
@@ -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 |
@@ -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 */ |
@@ -0,0 +1,286 @@ | |||
/* | |||
Copyright (c) 2012, Broadcom Europe Ltd | |||
All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright | |||
notice, this list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright | |||
notice, this list of conditions and the following disclaimer in the | |||
documentation and/or other materials provided with the distribution. | |||
* Neither the name of the copyright holder nor the | |||
names of its contributors may be used to endorse or promote products | |||
derived from this software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY | |||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
#ifndef MMAL_PORT_H | |||
#define MMAL_PORT_H | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** \defgroup MmalPort Ports | |||
* Definition of a MMAL port and its associated API */ | |||
/* @{ */ | |||
#include "mmal_types.h" | |||
#include "mmal_format.h" | |||
#include "mmal_buffer.h" | |||
#include "mmal_parameters.h" | |||
/** List of port types */ | |||
typedef enum | |||
{ | |||
MMAL_PORT_TYPE_UNKNOWN = 0, /**< Unknown port type */ | |||
MMAL_PORT_TYPE_CONTROL, /**< Control port */ | |||
MMAL_PORT_TYPE_INPUT, /**< Input port */ | |||
MMAL_PORT_TYPE_OUTPUT, /**< Output port */ | |||
MMAL_PORT_TYPE_CLOCK, /**< Clock port */ | |||
MMAL_PORT_TYPE_INVALID = 0xffffffff /**< Dummy value to force 32bit enum */ | |||
} MMAL_PORT_TYPE_T; | |||
/** \name Port capabilities | |||
* \anchor portcapabilities | |||
* The following flags describe the capabilities advertised by a port */ | |||
/* @{ */ | |||
/** The port is pass-through and doesn't need buffer headers allocated */ | |||
#define MMAL_PORT_CAPABILITY_PASSTHROUGH 0x01 | |||
/** The port wants to allocate the buffer payloads. This signals a preference that | |||
* payload allocation should be done on this port for efficiency reasons. */ | |||
#define MMAL_PORT_CAPABILITY_ALLOCATION 0x02 | |||
/** The port supports format change events. This applies to input ports and is used | |||
* to let the client know whether the port supports being reconfigured via a format | |||
* change event (i.e. without having to disable the port). */ | |||
#define MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE 0x04 | |||
/* @} */ | |||
/** Definition of a port. | |||
* A port is the entity that is exposed by components to receive or transmit | |||
* buffer headers (\ref MMAL_BUFFER_HEADER_T). A port is defined by its | |||
* \ref MMAL_ES_FORMAT_T. | |||
* | |||
* It may be possible to override the buffer requirements of a port by using | |||
* the MMAL_PARAMETER_BUFFER_REQUIREMENTS parameter. | |||
*/ | |||
typedef struct MMAL_PORT_T | |||
{ | |||
struct MMAL_PORT_PRIVATE_T *priv; /**< Private member used by the framework */ | |||
const char *name; /**< Port name. Used for debugging purposes (Read Only) */ | |||
MMAL_PORT_TYPE_T type; /**< Type of the port (Read Only) */ | |||
uint16_t index; /**< Index of the port in its type list (Read Only) */ | |||
uint16_t index_all; /**< Index of the port in the list of all ports (Read Only) */ | |||
uint32_t is_enabled; /**< Indicates whether the port is enabled or not (Read Only) */ | |||
MMAL_ES_FORMAT_T *format; /**< Format of the elementary stream */ | |||
uint32_t buffer_num_min; /**< Minimum number of buffers the port requires (Read Only). | |||
This is set by the component. */ | |||
uint32_t buffer_size_min; /**< Minimum size of buffers the port requires (Read Only). | |||
This is set by the component. */ | |||
uint32_t buffer_alignment_min; /**< Minimum alignment requirement for the buffers (Read Only). | |||
A value of zero means no special alignment requirements. | |||
This is set by the component. */ | |||
uint32_t buffer_num_recommended; /**< Number of buffers the port recommends for optimal performance (Read Only). | |||
A value of zero means no special recommendation. | |||
This is set by the component. */ | |||
uint32_t buffer_size_recommended; /**< Size of buffers the port recommends for optimal performance (Read Only). | |||
A value of zero means no special recommendation. | |||
This is set by the component. */ | |||
uint32_t buffer_num; /**< Actual number of buffers the port will use. | |||
This is set by the client. */ | |||
uint32_t buffer_size; /**< Actual maximum size of the buffers that will be sent | |||
to the port. This is set by the client. */ | |||
struct MMAL_COMPONENT_T *component; /**< Component this port belongs to (Read Only) */ | |||
struct MMAL_PORT_USERDATA_T *userdata; /**< Field reserved for use by the client */ | |||
uint32_t capabilities; /**< Flags describing the capabilities of a port (Read Only). | |||
* Bitwise combination of \ref portcapabilities "Port capabilities" | |||
* values. | |||
*/ | |||
} MMAL_PORT_T; | |||
/** Commit format changes on a port. | |||
* | |||
* @param port The port for which format changes are to be committed. | |||
* @return MMAL_SUCCESS on success | |||
*/ | |||
MMAL_STATUS_T mmal_port_format_commit(MMAL_PORT_T *port); | |||
/** Definition of the callback used by a port to send a \ref MMAL_BUFFER_HEADER_T | |||
* back to the user. | |||
* | |||
* @param port The port sending the buffer header. | |||
* @param buffer The buffer header being sent. | |||
*/ | |||
typedef void (*MMAL_PORT_BH_CB_T)(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer); | |||
/** Enable processing on a port | |||
* | |||
* If this port is connected to another, the given callback must be NULL, while for a | |||
* disconnected port, the callback must be non-NULL. | |||
* | |||
* If this is a connected output port and is successfully enabled: | |||
* <ul> | |||
* <li>The port shall be populated with a pool of buffers, allocated as required, according | |||
* to the buffer_num and buffer_size values. | |||
* <li>The input port to which it is connected shall be set to the same buffer | |||
* configuration and then be enabled. Should that fail, the original port shall be | |||
* disabled. | |||
* </ul> | |||
* | |||
* @param port port to enable | |||
* @param cb callback use by the port to send a \ref MMAL_BUFFER_HEADER_T back | |||
* @return MMAL_SUCCESS on success | |||
*/ | |||
MMAL_STATUS_T mmal_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb); | |||
/** Disable processing on a port | |||
* | |||
* Disabling a port will stop all processing on this port and return all (non-processed) | |||
* buffer headers to the client. | |||
* | |||
* If this is a connected output port, the input port to which it is connected shall | |||
* also be disabled. Any buffer pool shall be released. | |||
* | |||
* @param port port to disable | |||
* @return MMAL_SUCCESS on success | |||
*/ | |||
MMAL_STATUS_T mmal_port_disable(MMAL_PORT_T *port); | |||
/** Ask a port to release all the buffer headers it currently has. | |||
* | |||
* Flushing a port will ask the port to send all the buffer headers it currently has | |||
* to the client. Flushing is an asynchronous request and the flush call will | |||
* return before all the buffer headers are returned to the client. | |||
* It is up to the client to keep a count on the buffer headers to know when the | |||
* flush operation has completed. | |||
* It is also important to note that flushing will also reset the state of the port | |||
* and any processing which was buffered by the port will be lost. | |||
* | |||
* \attention Flushing a connected port behaviour TBD. | |||
* | |||
* @param port The port to flush. | |||
* @return MMAL_SUCCESS on success | |||
*/ | |||
MMAL_STATUS_T mmal_port_flush(MMAL_PORT_T *port); | |||
/** Set a parameter on a port. | |||
* | |||
* @param port The port to which the request is sent. | |||
* @param param The pointer to the header of the parameter to set. | |||
* @return MMAL_SUCCESS on success | |||
*/ | |||
MMAL_STATUS_T mmal_port_parameter_set(MMAL_PORT_T *port, | |||
const MMAL_PARAMETER_HEADER_T *param); | |||
/** Get a parameter from a port. | |||
* The size field must be set on input to the maximum size of the parameter | |||
* (including the header) and will be set on output to the actual size of the | |||
* parameter retrieved. | |||
* | |||
* \note If MMAL_ENOSPC is returned, the parameter is larger than the size | |||
* given. The given parameter will have been filled up to its size and then | |||
* the size field set to the full parameter's size. This can be used to | |||
* resize the parameter buffer so that a second call should succeed. | |||
* | |||
* @param port The port to which the request is sent. | |||
* @param param The pointer to the header of the parameter to get. | |||
* @return MMAL_SUCCESS on success | |||
*/ | |||
MMAL_STATUS_T mmal_port_parameter_get(MMAL_PORT_T *port, | |||
MMAL_PARAMETER_HEADER_T *param); | |||
/** Send a buffer header to a port. | |||
* | |||
* @param port The port to which the buffer header is to be sent. | |||
* @param buffer The buffer header to send. | |||
* @return MMAL_SUCCESS on success | |||
*/ | |||
MMAL_STATUS_T mmal_port_send_buffer(MMAL_PORT_T *port, | |||
MMAL_BUFFER_HEADER_T *buffer); | |||
/** Connect an output port to an input port. | |||
* | |||
* When connected and enabled, buffers will automatically progress from the | |||
* output port to the input port when they become available, and released back | |||
* to the output port when no longer required by the input port. | |||
* | |||
* Ports can be given either way around, but one must be an output port and | |||
* the other must be an input port. Neither can be connected or enabled | |||
* already. The format of the output port will be applied to the input port | |||
* on connection. | |||
* | |||
* @param port One of the ports to connect. | |||
* @param other_port The other port to connect. | |||
* @return MMAL_SUCCESS on success. | |||
*/ | |||
MMAL_STATUS_T mmal_port_connect(MMAL_PORT_T *port, MMAL_PORT_T *other_port); | |||
/** Disconnect a connected port. | |||
* | |||
* If the port is not connected, an error will be returned. Otherwise, if the | |||
* ports are enabled, they will be disabled and any buffer pool created will be | |||
* freed. | |||
* | |||
* @param port The ports to disconnect. | |||
* @return MMAL_SUCCESS on success. | |||
*/ | |||
MMAL_STATUS_T mmal_port_disconnect(MMAL_PORT_T *port); | |||
/** Allocate a payload buffer. | |||
* This allows a client to allocate memory for a payload buffer based on the preferences | |||
* of a port. This for instance will allow the port to allocate memory which can be shared | |||
* between the host processor and videocore. | |||
* | |||
* See \ref mmal_pool_create_with_allocator(). | |||
* | |||
* @param port Port responsible for allocating the memory. | |||
* @param payload_size Size of the payload buffer which will be allocated. | |||
* | |||
* @return Pointer to the allocated memory. | |||
*/ | |||
uint8_t *mmal_port_payload_alloc(MMAL_PORT_T *port, uint32_t payload_size); | |||
/** Free a payload buffer. | |||
* This allows a client to free memory allocated by a previous call to \ref mmal_port_payload_alloc. | |||
* | |||
* See \ref mmal_pool_create_with_allocator(). | |||
* | |||
* @param port Port responsible for allocating the memory. | |||
* @param payload Pointer to the memory to free. | |||
*/ | |||
void mmal_port_payload_free(MMAL_PORT_T *port, uint8_t *payload); | |||
/** Get an empty event buffer header from a port | |||
* | |||
* @param port The port from which to get the event buffer header. | |||
* @param buffer The address of a buffer header pointer, which will be set on return. | |||
* @param event The specific event FourCC required. See the \ref MmalEvents "pre-defined events". | |||
* @return MMAL_SUCCESS on success | |||
*/ | |||
MMAL_STATUS_T mmal_port_event_get(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T **buffer, uint32_t event); | |||
/* @} */ | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif /* MMAL_PORT_H */ |
@@ -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 */ |
@@ -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 */ |
@@ -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 |
@@ -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 |
@@ -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) |
@@ -0,0 +1,130 @@ | |||
/* | |||
Copyright (c) 2012, Broadcom Europe Ltd | |||
All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright | |||
notice, this list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright | |||
notice, this list of conditions and the following disclaimer in the | |||
documentation and/or other materials provided with the distribution. | |||
* Neither the name of the copyright holder nor the | |||
names of its contributors may be used to endorse or promote products | |||
derived from this software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY | |||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
/** \file | |||
* OpenMAX IL adaptation layer for MMAL | |||
*/ | |||
#include "interface/vmcs_host/khronos/IL/OMX_Core.h" | |||
#include "interface/vmcs_host/khronos/IL/OMX_Component.h" | |||
#include "interface/vmcs_host/khronos/IL/OMX_Video.h" | |||
#include "interface/vmcs_host/khronos/IL/OMX_Audio.h" | |||
#include <mmal.h> | |||
#include <util/mmal_il.h> | |||
/* Define this to 1 if you want to log all buffer transfers */ | |||
#define ENABLE_MMAL_EXTRA_LOGGING 0 | |||
#ifndef MMALOMX_EXPORT | |||
# define MMALOMX_EXPORT(a) a | |||
#endif | |||
#ifndef MMALOMX_IMPORT | |||
# define MMALOMX_IMPORT(a) a | |||
#endif | |||
#define MAX_MARKS_NUM 2 | |||
#define MAX_ENCODINGS_NUM 20 | |||
/** Per-port context data */ | |||
typedef struct MMALOMX_PORT_T | |||
{ | |||
struct MMALOMX_COMPONENT_T *component; | |||
MMAL_PORT_T *mmal; | |||
OMX_DIRTYPE direction; | |||
unsigned int index; | |||
unsigned int buffers; | |||
unsigned int buffers_in_transit; | |||
MMAL_BOOL_T buffers_allocated:1; | |||
MMAL_BOOL_T enabled:1; | |||
MMAL_BOOL_T populated:1; | |||
MMAL_BOOL_T zero_copy:1; | |||
MMAL_BOOL_T no_cropping:1; | |||
MMAL_BOOL_T format_changed:1; | |||
MMAL_POOL_T *pool; | |||
uint32_t actions; | |||
OMX_MARKTYPE marks[MAX_MARKS_NUM]; | |||
unsigned int marks_first:8; | |||
unsigned int marks_num:8; | |||
OMX_FORMAT_PARAM_TYPE format_param; | |||
MMAL_PARAMETER_HEADER_T encodings_header; | |||
MMAL_FOURCC_T encodings[MAX_ENCODINGS_NUM]; | |||
unsigned int encodings_num; | |||
} MMALOMX_PORT_T; | |||
/** Component context data */ | |||
typedef struct MMALOMX_COMPONENT_T { | |||
OMX_COMPONENTTYPE omx; /**< OMX component type structure */ | |||
unsigned int registry_id; | |||
const char *name; | |||
uint32_t role; | |||
OMX_CALLBACKTYPE callbacks; | |||
OMX_PTR callbacks_data; | |||
struct MMAL_COMPONENT_T *mmal; | |||
OMX_STATETYPE state; | |||
unsigned int state_transition; | |||
MMALOMX_PORT_T *ports; | |||
unsigned int ports_num; | |||
unsigned int ports_domain_num[4]; | |||
MMAL_BOOL_T actions_running; | |||
OMX_U32 group_id; | |||
OMX_U32 group_priority; | |||
/* Support for command queues */ | |||
MMAL_POOL_T *cmd_pool; | |||
MMAL_QUEUE_T *cmd_queue; | |||
VCOS_THREAD_T cmd_thread; | |||
MMAL_BOOL_T cmd_thread_used; | |||
VCOS_SEMAPHORE_T cmd_sema; | |||
VCOS_MUTEX_T lock; /**< Used to protect component state */ | |||
VCOS_MUTEX_T lock_port; /**< Used to protect port state */ | |||
} MMALOMX_COMPONENT_T; | |||
OMX_ERRORTYPE mmalomx_callback_event_handler( | |||
MMALOMX_COMPONENT_T *component, | |||
OMX_EVENTTYPE eEvent, | |||
OMX_U32 nData1, | |||
OMX_U32 nData2, | |||
OMX_PTR pEventData); | |||
#define MMALOMX_LOCK(a) vcos_mutex_lock(&a->lock) | |||
#define MMALOMX_UNLOCK(a) vcos_mutex_unlock(&a->lock) | |||
#define MMALOMX_LOCK_PORT(a,b) vcos_mutex_lock(&a->lock_port) | |||
#define MMALOMX_UNLOCK_PORT(a,b) vcos_mutex_unlock(&a->lock_port) | |||
@@ -0,0 +1,235 @@ | |||
/* | |||
Copyright (c) 2012, Broadcom Europe Ltd | |||
All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright | |||
notice, this list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright | |||
notice, this list of conditions and the following disclaimer in the | |||
documentation and/or other materials provided with the distribution. | |||
* Neither the name of the copyright holder nor the | |||
names of its contributors may be used to endorse or promote products | |||
derived from this software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY | |||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
#include "mmalomx.h" | |||
#include "mmalomx_buffer.h" | |||
#include "mmalomx_commands.h" | |||
#include "mmalomx_marks.h" | |||
#include "mmalomx_logging.h" | |||
#include <util/mmal_util.h> | |||
/*****************************************************************************/ | |||
OMX_ERRORTYPE mmalomx_buffer_send( | |||
MMALOMX_COMPONENT_T *component, | |||
OMX_BUFFERHEADERTYPE *omx_buffer, | |||
OMX_DIRTYPE direction) | |||
{ | |||
OMX_ERRORTYPE status = OMX_ErrorNone; | |||
MMAL_BUFFER_HEADER_T *mmal_buffer; | |||
MMAL_STATUS_T mmal_status; | |||
MMALOMX_PORT_T *port; | |||
unsigned int index; | |||
/* Sanity checks */ | |||
if (!component) | |||
return OMX_ErrorInvalidComponent; | |||
if (component->state == OMX_StateInvalid) | |||
return OMX_ErrorInvalidState; | |||
if (!omx_buffer || omx_buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE) || | |||
omx_buffer->nOffset + omx_buffer->nFilledLen > omx_buffer->nAllocLen) | |||
return OMX_ErrorBadParameter; | |||
index = direction == OMX_DirInput ? omx_buffer->nInputPortIndex : omx_buffer->nOutputPortIndex; | |||
if (index >= component->ports_num) | |||
return OMX_ErrorBadPortIndex; | |||
port = &component->ports[index]; | |||
if (port->direction != direction) | |||
return OMX_ErrorBadPortIndex; | |||
MMALOMX_LOCK_PORT(component, port); | |||
if (component->state != OMX_StatePause && component->state != OMX_StateExecuting) | |||
status = OMX_ErrorIncorrectStateOperation; | |||
if (!port->enabled /* FIXME: || flushing || pending idle */) | |||
status = OMX_ErrorIncorrectStateOperation; | |||
if (status != OMX_ErrorNone) | |||
goto error; | |||
mmal_buffer = mmal_queue_get( port->pool->queue ); | |||
if (!vcos_verify(mmal_buffer)) /* Should never happen */ | |||
{ | |||
status = OMX_ErrorUndefined; | |||
goto error; | |||
} | |||
mmalomx_mark_process_incoming(component, port, omx_buffer); | |||
mmal_buffer->user_data = (void *)omx_buffer; | |||
mmalil_buffer_header_to_mmal(mmal_buffer, omx_buffer); | |||
mmal_status = mmal_port_send_buffer(port->mmal, mmal_buffer); | |||
if (!vcos_verify(mmal_status == MMAL_SUCCESS)) | |||
{ | |||
LOG_ERROR("failed to send buffer on %s", port->mmal->name); | |||
mmal_queue_put_back( port->pool->queue, mmal_buffer ); | |||
status = mmalil_error_to_omx(mmal_status); | |||
} | |||
else | |||
{ | |||
port->buffers_in_transit++; | |||
} | |||
error: | |||
MMALOMX_UNLOCK_PORT(component, port); | |||
return status; | |||
} | |||
/*****************************************************************************/ | |||
static void mmalomx_buffer_event( | |||
MMALOMX_PORT_T *port, | |||
MMAL_BUFFER_HEADER_T *mmal_buffer) | |||
{ | |||
MMALOMX_COMPONENT_T *component = port->component; | |||
MMAL_EVENT_FORMAT_CHANGED_T *event; | |||
LOG_TRACE("hComponent %p, port %i, event %4.4s", component, port->index, | |||
(char *)&mmal_buffer->cmd); | |||
if (mmal_buffer->cmd == MMAL_EVENT_ERROR ) | |||
{ | |||
mmalomx_callback_event_handler(component, OMX_EventError, | |||
mmalil_error_to_omx(*(MMAL_STATUS_T *)mmal_buffer->data), 0, NULL); | |||
return; | |||
} | |||
event = mmal_event_format_changed_get(mmal_buffer); | |||
if (event && port->mmal->type == MMAL_PORT_TYPE_OUTPUT && | |||
port->mmal->format->type == MMAL_ES_TYPE_VIDEO) | |||
{ | |||
uint32_t diff = mmal_format_compare(event->format, port->mmal->format); | |||
MMAL_ES_FORMAT_T *format = port->mmal->format; | |||
MMAL_VIDEO_FORMAT_T video = format->es->video; | |||
/* Update the port settings with the new values */ | |||
mmal_format_copy(format, event->format); | |||
port->mmal->buffer_num_min = event->buffer_num_min; | |||
port->mmal->buffer_size_min = event->buffer_size_min; | |||
port->format_changed = MMAL_TRUE; | |||
if ((diff & MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_ASPECT_RATIO) && | |||
/* Do not report a change if going from unspecified to 1:1 */ | |||
!(format->es->video.par.num == format->es->video.par.den && !video.par.num)) | |||
{ | |||
LOG_DEBUG("aspect ratio change %ix%i->%ix%i", (int)video.par.num, (int)video.par.den, | |||
(int)format->es->video.par.num, (int)format->es->video.par.den); | |||
mmalomx_callback_event_handler(component, OMX_EventPortSettingsChanged, | |||
port->index, OMX_IndexParamBrcmPixelAspectRatio, NULL); | |||
} | |||
if (diff & (MMAL_ES_FORMAT_COMPARE_FLAG_ENCODING| | |||
MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_RESOLUTION| | |||
MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_CROPPING)) | |||
{ | |||
LOG_DEBUG("format change %ix%i(%ix%i) -> %ix%i(%ix%i)", | |||
(int)video.width, (int)video.height, | |||
(int)video.crop.width, (int)video.crop.height, | |||
(int)format->es->video.width, (int)format->es->video.height, | |||
(int)format->es->video.crop.width, (int)format->es->video.crop.height); | |||
mmalomx_callback_event_handler(component, OMX_EventPortSettingsChanged, | |||
port->index, 0, NULL); | |||
} | |||
} | |||
else if (event && port->mmal->type == MMAL_PORT_TYPE_OUTPUT && | |||
port->mmal->format->type == MMAL_ES_TYPE_AUDIO) | |||
{ | |||
uint32_t diff = mmal_format_compare(event->format, port->mmal->format); | |||
MMAL_ES_FORMAT_T *format = port->mmal->format; | |||
MMAL_AUDIO_FORMAT_T audio = format->es->audio; | |||
/* Update the port settings with the new values */ | |||
mmal_format_copy(format, event->format); | |||
port->mmal->buffer_num_min = event->buffer_num_min; | |||
port->mmal->buffer_size_min = event->buffer_size_min; | |||
port->format_changed = MMAL_TRUE; | |||
if (diff) | |||
{ | |||
LOG_DEBUG("format change %ich, %iHz, %ibps -> %ich, %iHz, %ibps", | |||
(int)audio.channels, (int)audio.sample_rate, | |||
(int)audio.bits_per_sample, | |||
(int)format->es->audio.channels, | |||
(int)format->es->audio.sample_rate, | |||
(int)format->es->audio.bits_per_sample); | |||
mmalomx_callback_event_handler(component, OMX_EventPortSettingsChanged, | |||
port->index, 0, NULL); | |||
} | |||
} | |||
} | |||
/*****************************************************************************/ | |||
OMX_ERRORTYPE mmalomx_buffer_return( | |||
MMALOMX_PORT_T *port, | |||
MMAL_BUFFER_HEADER_T *mmal_buffer) | |||
{ | |||
MMALOMX_COMPONENT_T *component = port->component; | |||
OMX_BUFFERHEADERTYPE *omx_buffer = (OMX_BUFFERHEADERTYPE *)mmal_buffer->user_data; | |||
MMAL_BOOL_T signal; | |||
if (mmal_buffer->cmd) | |||
{ | |||
mmalomx_buffer_event(port, mmal_buffer); | |||
mmal_buffer_header_release(mmal_buffer); | |||
return OMX_ErrorNone; | |||
} | |||
if (ENABLE_MMAL_EXTRA_LOGGING) | |||
LOG_TRACE("hComponent %p, port %i, pBuffer %p", component, | |||
port->index, omx_buffer); | |||
vcos_assert(omx_buffer->pBuffer == mmal_buffer->data); | |||
mmalil_buffer_header_to_omx(omx_buffer, mmal_buffer); | |||
mmal_buffer_header_release(mmal_buffer); | |||
if ((omx_buffer->nFlags & OMX_BUFFERFLAG_EOS) && port->direction == OMX_DirOutput) | |||
{ | |||
mmalomx_callback_event_handler(component, OMX_EventBufferFlag, | |||
port->index, omx_buffer->nFlags, NULL); | |||
} | |||
mmalomx_mark_process_outgoing(component, port, omx_buffer); | |||
if (port->direction == OMX_DirInput) | |||
component->callbacks.EmptyBufferDone((OMX_HANDLETYPE)&component->omx, | |||
component->callbacks_data, omx_buffer ); | |||
else | |||
component->callbacks.FillBufferDone((OMX_HANDLETYPE)&component->omx, | |||
component->callbacks_data, omx_buffer ); | |||
MMALOMX_LOCK_PORT(component, port); | |||
signal = port->actions & MMALOMX_ACTION_CHECK_FLUSHED; | |||
port->buffers_in_transit--; | |||
MMALOMX_UNLOCK_PORT(component, port); | |||
if (signal) | |||
mmalomx_commands_actions_signal(component); | |||
return OMX_ErrorNone; | |||
} | |||
@@ -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); |
@@ -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); | |||
} | |||
} | |||
@@ -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); | |||
@@ -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)]; | |||
} |
@@ -0,0 +1,46 @@ | |||
/* | |||
Copyright (c) 2012, Broadcom Europe Ltd | |||
All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright | |||
notice, this list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright | |||
notice, this list of conditions and the following disclaimer in the | |||
documentation and/or other materials provided with the distribution. | |||
* Neither the name of the copyright holder nor the | |||
names of its contributors may be used to endorse or promote products | |||
derived from this software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY | |||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
/** \file | |||
* OpenMAX IL adaptation layer for MMAL - Logging functions | |||
*/ | |||
#include "mmal_common.h" | |||
#include "interface/vcos/vcos_logging.h" | |||
#define VCOS_LOG_CATEGORY (&mmalomx_log_category) | |||
extern VCOS_LOG_CAT_T mmalomx_log_category; | |||
#include <mmal_logging.h> | |||
void mmalomx_logging_init(void); | |||
void mmalomx_logging_deinit(void); | |||
const char *mmalomx_param_to_string(OMX_INDEXTYPE param); | |||
const char *mmalomx_cmd_to_string(OMX_COMMANDTYPE cmd); | |||
const char *mmalomx_state_to_string(OMX_STATETYPE state); | |||
const char *mmalomx_event_to_string(OMX_EVENTTYPE event); | |||
const char *mmalomx_error_to_string(OMX_ERRORTYPE error); |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
@@ -0,0 +1,578 @@ | |||
/* | |||
Copyright (c) 2012, Broadcom Europe Ltd | |||
All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright | |||
notice, this list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright | |||
notice, this list of conditions and the following disclaimer in the | |||
documentation and/or other materials provided with the distribution. | |||
* Neither the name of the copyright holder nor the | |||
names of its contributors may be used to endorse or promote products | |||
derived from this software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY | |||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
#include "interface/vmcs_host/khronos/IL/OMX_Broadcom.h" | |||
#include "mmalomx.h" | |||
#include "mmalomx_parameters.h" | |||
#include "mmalomx_util_params.h" | |||
#include "mmalomx_roles.h" | |||
#include "mmalomx_registry.h" | |||
#include "mmalomx_logging.h" | |||
#include <util/mmal_util.h> | |||
#include <util/mmal_util_params.h> | |||
#include <util/mmal_util_rational.h> | |||
#define PARAM_GET_PORT(port, component, index) \ | |||
if (index >= component->ports_num) return OMX_ErrorBadPortIndex; \ | |||
port = &component->ports[index] | |||
#define MMALOMX_PARAM_GENERIC_MAX 256 | |||
/** A structure capable of holding any OMX parameter that contains a port */ | |||
typedef struct MMALOMX_PARAM_OMX_GENERIC_T | |||
{ | |||
MMALOMX_PARAM_OMX_HEADER_T header; | |||
uint8_t data[MMALOMX_PARAM_GENERIC_MAX]; | |||
} MMALOMX_PARAM_OMX_GENERIC_T; | |||
/** A structure capable of holding any OMX parameter that doesn't contain a port */ | |||
typedef struct MMALOMX_PARAM_OMX_GENERIC_PORTLESS_T | |||
{ | |||
MMALOMX_PARAM_OMX_HEADER_PORTLESS_T hdr; | |||
uint8_t data[MMALOMX_PARAM_GENERIC_MAX]; | |||
} MMALOMX_PARAM_OMX_GENERIC_PORTLESS_T; | |||
/** A structure capable of holding any MMAL parameter */ | |||
typedef struct MMALOMX_PARAM_MMAL_GENERIC_T | |||
{ | |||
MMAL_PARAMETER_HEADER_T header; | |||
uint8_t data[MMALOMX_PARAM_GENERIC_MAX]; | |||
} MMALOMX_PARAM_MMAL_GENERIC_T; | |||
static OMX_ERRORTYPE mmalomx_parameter_set_xlat(MMALOMX_COMPONENT_T *component, | |||
OMX_INDEXTYPE nParamIndex, OMX_PTR pParam) | |||
{ | |||
const MMALOMX_PARAM_TRANSLATION_T *xlat = mmalomx_find_parameter_from_omx_id(nParamIndex); | |||
MMALOMX_PARAM_OMX_HEADER_T *omx_header = (MMALOMX_PARAM_OMX_HEADER_T *)pParam; | |||
MMALOMX_PARAM_MMAL_GENERIC_T mmal_generic; | |||
MMAL_PARAMETER_HEADER_T *mmal_header = &mmal_generic.header; | |||
MMAL_PORT_T *mmal_port = component->mmal->control; | |||
MMAL_STATUS_T status; | |||
if (!xlat) | |||
{ | |||
LOG_DEBUG("no translation for omx id 0x%08x", nParamIndex); | |||
return OMX_ErrorNotImplemented; | |||
} | |||
if (!xlat->portless) | |||
{ | |||
if (omx_header->nSize < sizeof(*omx_header)) | |||
return OMX_ErrorBadParameter; | |||
if (omx_header->nPortIndex >= component->ports_num) | |||
return OMX_ErrorBadPortIndex; | |||
mmal_port = component->ports[omx_header->nPortIndex].mmal; | |||
} | |||
if (omx_header->nSize < xlat->omx_size) | |||
return OMX_ErrorBadParameter; | |||
/* Handle the direct case first */ | |||
if (xlat->type == MMALOMX_PARAM_TRANSLATION_TYPE_DIRECT) | |||
{ | |||
mmal_header = (MMAL_PARAMETER_HEADER_T *)(((uint8_t *)pParam) + (xlat->portless ? 0 : 4)); | |||
mmal_generic.header = *mmal_header; | |||
mmal_header->size = omx_header->nSize - (xlat->portless ? 0 : 4); | |||
mmal_header->id = xlat->mmal_id; | |||
status = mmal_port_parameter_set(mmal_port, mmal_header); | |||
*mmal_header = mmal_generic.header; | |||
return mmalil_error_to_omx(status); | |||
} | |||
if (!xlat->fn.generic && !xlat->fn.simple) | |||
{ | |||
// FIXME | |||
return OMX_ErrorNotImplemented; | |||
} | |||
// FIXME: check size of mmal_generic is sufficient | |||
if (sizeof(mmal_generic) < xlat->mmal_size) | |||
return OMX_ErrorBadParameter; | |||
mmal_header->size = xlat->mmal_size; | |||
mmal_header->id = xlat->mmal_id; | |||
if (xlat->fn.generic) | |||
status = xlat->fn.generic(MMALOMX_PARAM_MAPPING_TO_MMAL, xlat, mmal_header, pParam, mmal_port); | |||
else | |||
status = xlat->fn.simple(MMALOMX_PARAM_MAPPING_TO_MMAL, mmal_header, pParam); | |||
if (status != MMAL_SUCCESS) | |||
goto error; | |||
status = mmal_port_parameter_set(mmal_port, mmal_header); | |||
error: | |||
return mmalil_error_to_omx(status); | |||
} | |||
static OMX_ERRORTYPE mmalomx_parameter_get_xlat(MMALOMX_COMPONENT_T *component, | |||
OMX_INDEXTYPE nParamIndex, OMX_PTR pParam) | |||
{ | |||
const MMALOMX_PARAM_TRANSLATION_T *xlat = mmalomx_find_parameter_from_omx_id(nParamIndex); | |||
MMALOMX_PARAM_OMX_HEADER_T *omx_header = (MMALOMX_PARAM_OMX_HEADER_T *)pParam; | |||
MMALOMX_PARAM_MMAL_GENERIC_T mmal_generic; | |||
MMAL_PARAMETER_HEADER_T *mmal_header = &mmal_generic.header; | |||
MMAL_PORT_T *mmal_port = component->mmal->control; | |||
MMAL_STATUS_T status = MMAL_SUCCESS; | |||
if (!xlat) | |||
return OMX_ErrorNotImplemented; | |||
if (!xlat->portless) | |||
{ | |||
if (omx_header->nSize < sizeof(*omx_header)) | |||
return OMX_ErrorBadParameter; | |||
if (omx_header->nPortIndex >= component->ports_num) | |||
return OMX_ErrorBadPortIndex; | |||
mmal_port = component->ports[omx_header->nPortIndex].mmal; | |||
} | |||
if (omx_header->nSize < xlat->omx_size) | |||
return OMX_ErrorBadParameter; | |||
/* Handle the direct case first */ | |||
if (xlat->type == MMALOMX_PARAM_TRANSLATION_TYPE_DIRECT) | |||
{ | |||
OMX_U32 size; | |||
mmal_header = (MMAL_PARAMETER_HEADER_T *)(((uint8_t *)pParam) + (xlat->portless ? 0 : 4)); | |||
mmal_generic.header = *mmal_header; | |||
mmal_header->size = omx_header->nSize - (xlat->portless ? 0 : 4); | |||
mmal_header->id = xlat->mmal_id; | |||
status = mmal_port_parameter_get(mmal_port, mmal_header); | |||
*mmal_header = mmal_generic.header; | |||
size = mmal_header->size + (xlat->portless ? 0 : 4); | |||
omx_header->nSize = size; | |||
return mmalil_error_to_omx(status); | |||
} | |||
if (xlat->fn.custom) | |||
{ | |||
return 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; | |||
} |
@@ -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); |
@@ -0,0 +1,159 @@ | |||
/* | |||
Copyright (c) 2012, Broadcom Europe Ltd | |||
All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright | |||
notice, this list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright | |||
notice, this list of conditions and the following disclaimer in the | |||
documentation and/or other materials provided with the distribution. | |||
* Neither the name of the copyright holder nor the | |||
names of its contributors may be used to endorse or promote products | |||
derived from this software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY | |||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
#include "mmalomx.h" | |||
#include "mmalomx_roles.h" | |||
#include "mmalomx_registry.h" | |||
#include "mmalomx_logging.h" | |||
#include <util/mmal_default_components.h> | |||
#ifndef ENABLE_MMALOMX_AUDIO_HW_DECODER | |||
# define ENABLE_MMALOMX_AUDIO_HW_DECODER 0 | |||
#endif | |||
#ifndef ENABLE_MMALOMX_AUDIO_SPDIF | |||
# define ENABLE_MMALOMX_AUDIO_SPDIF 1 | |||
#endif | |||
static const struct { | |||
const char *omx; | |||
const char *omx_prefix; | |||
const char *mmal; | |||
MMALOMX_ROLE_T roles[MMALOMX_ROLE_MAX]; | |||
} mmalomx_components[] = | |||
{ | |||
{"video.hw.decoder", 0, MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, | |||
{MMALOMX_ROLE_VIDEO_DECODER_H263, MMALOMX_ROLE_VIDEO_DECODER_MPEG2, | |||
MMALOMX_ROLE_VIDEO_DECODER_MPEG4, MMALOMX_ROLE_VIDEO_DECODER_AVC, | |||
MMALOMX_ROLE_VIDEO_DECODER_WMV, MMALOMX_ROLE_VIDEO_DECODER_VPX, | |||
MMALOMX_ROLE_UNDEFINED}}, | |||
{"video.hw.decoder.secure", 0, "drm_alloc.video_decode", | |||
{MMALOMX_ROLE_VIDEO_DECODER_H263, MMALOMX_ROLE_VIDEO_DECODER_MPEG2, | |||
MMALOMX_ROLE_VIDEO_DECODER_MPEG4, MMALOMX_ROLE_VIDEO_DECODER_AVC, | |||
MMALOMX_ROLE_VIDEO_DECODER_WMV, MMALOMX_ROLE_VIDEO_DECODER_VPX, | |||
MMALOMX_ROLE_UNDEFINED}}, | |||
{"video.hw.decoder.divx_drm", 0, "aggregator.pipeline:divx_drm:vc.video_decode", | |||
{MMALOMX_ROLE_VIDEO_DECODER_MPEG4, MMALOMX_ROLE_UNDEFINED}}, | |||
{"video.vpx.decoder", 0, "libvpx", | |||
{MMALOMX_ROLE_VIDEO_DECODER_VPX, MMALOMX_ROLE_UNDEFINED}}, | |||
{"video.hw.encoder", 0, MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER, | |||
{MMALOMX_ROLE_VIDEO_ENCODER_H263, MMALOMX_ROLE_VIDEO_ENCODER_MPEG4, | |||
MMALOMX_ROLE_VIDEO_ENCODER_AVC, MMALOMX_ROLE_UNDEFINED}}, | |||
{"AIV.play", "", "aivplay", | |||
{MMALOMX_ROLE_AIV_PLAY_101, MMALOMX_ROLE_AIV_PLAY_AVCDDP, MMALOMX_ROLE_UNDEFINED}}, | |||
{"AIV.play.avcddp", "", "aivplay.ddp", | |||
{MMALOMX_ROLE_AIV_PLAY_AVCDDP, MMALOMX_ROLE_AIV_PLAY_101, MMALOMX_ROLE_UNDEFINED}}, | |||
#if ENABLE_MMALOMX_AUDIO_HW_DECODER | |||
{"audio.hw.decoder", 0, "vc.ril.audio_decode", | |||
{MMALOMX_ROLE_AUDIO_DECODER_AAC, MMALOMX_ROLE_AUDIO_DECODER_MPGA_L1, | |||
MMALOMX_ROLE_AUDIO_DECODER_MPGA_L2, MMALOMX_ROLE_AUDIO_DECODER_MPGA_L3, | |||
MMALOMX_ROLE_AUDIO_DECODER_DDP, MMALOMX_ROLE_UNDEFINED}}, | |||
#endif | |||
#if ENABLE_MMALOMX_AUDIO_SPDIF | |||
{"audio.spdif", 0, "spdif", | |||
{MMALOMX_ROLE_AUDIO_DECODER_DDP, MMALOMX_ROLE_UNDEFINED}}, | |||
#endif | |||
{0, 0, 0, {MMALOMX_ROLE_UNDEFINED}} | |||
}; | |||
int mmalomx_registry_find_component(const char *name) | |||
{ | |||
int i, prefix_size; | |||
const char *prefix; | |||
for (i = 0; mmalomx_components[i].omx; i++) | |||
{ | |||
/* Check the prefix first */ | |||
prefix = mmalomx_components[i].omx_prefix; | |||
if (!prefix) | |||
prefix = MMALOMX_COMPONENT_PREFIX; | |||
prefix_size = strlen(prefix); | |||
if (strncmp(name, prefix, prefix_size)) | |||
continue; | |||
/* Check the rest of the name */ | |||
if (!strcmp(name + prefix_size, mmalomx_components[i].omx)) | |||
break; | |||
} | |||
return mmalomx_components[i].mmal ? i : -1; | |||
} | |||
const char *mmalomx_registry_component_mmal(int id) | |||
{ | |||
if (id >= (int)MMAL_COUNTOF(mmalomx_components) || id < 0) | |||
id = MMAL_COUNTOF(mmalomx_components) - 1; | |||
return mmalomx_components[id].mmal; | |||
} | |||
MMALOMX_ROLE_T mmalomx_registry_component_roles(int id, unsigned int index) | |||
{ | |||
unsigned int i; | |||
if (id >= (int)MMAL_COUNTOF(mmalomx_components) || id < 0) | |||
id = MMAL_COUNTOF(mmalomx_components) - 1; | |||
for (i = 0; i < index; i++) | |||
if (mmalomx_components[id].roles[i] == MMALOMX_ROLE_UNDEFINED) | |||
break; | |||
return mmalomx_components[id].roles[i]; | |||
} | |||
MMAL_BOOL_T mmalomx_registry_component_supports_role(int id, MMALOMX_ROLE_T role) | |||
{ | |||
unsigned int i; | |||
if (id >= (int)MMAL_COUNTOF(mmalomx_components) || id < 0) | |||
id = MMAL_COUNTOF(mmalomx_components) - 1; | |||
for (i = 0; mmalomx_components[id].roles[i] != MMALOMX_ROLE_UNDEFINED; i++) | |||
if (mmalomx_components[id].roles[i] == role) | |||
return MMAL_TRUE; | |||
return MMAL_FALSE; | |||
} | |||
const char *mmalomx_registry_component_name(int id, const char **prefix) | |||
{ | |||
if (id >= (int)MMAL_COUNTOF(mmalomx_components) || id < 0) | |||
id = MMAL_COUNTOF(mmalomx_components) - 1; | |||
if (prefix) | |||
{ | |||
*prefix = mmalomx_components[id].omx_prefix; | |||
if (!*prefix) | |||
*prefix = MMALOMX_COMPONENT_PREFIX; | |||
} | |||
return mmalomx_components[id].omx; | |||
} |
@@ -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); |
@@ -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; | |||
} |
@@ -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); |
@@ -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; | |||
} |
@@ -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 */ |
@@ -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() | |||
}; |
@@ -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 |
@@ -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} |
@@ -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 |
@@ -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() | |||
}; |
@@ -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) |
@@ -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 <stdio.h> | |||
#define CHECK_STATUS(status, msg) if (status != MMAL_SUCCESS) { fprintf(stderr, msg"\n"); goto error; } | |||
static uint8_t codec_header_bytes[512]; | |||
static unsigned int codec_header_bytes_size = sizeof(codec_header_bytes); | |||
static FILE *source_file; | |||
/* Macros abstracting the I/O, just to make the example code clearer */ | |||
#define SOURCE_OPEN(uri) \ | |||
source_file = fopen(uri, "rb"); if (!source_file) goto error; | |||
#define SOURCE_READ_CODEC_CONFIG_DATA(bytes, size) \ | |||
size = fread(bytes, 1, size, source_file); rewind(source_file) | |||
#define SOURCE_READ_DATA_INTO_BUFFER(a) \ | |||
a->length = fread(a->data, 1, a->alloc_size - 128, source_file); \ | |||
a->offset = 0; a->pts = a->dts = MMAL_TIME_UNKNOWN | |||
#define SOURCE_CLOSE() \ | |||
if (source_file) fclose(source_file) | |||
/** Context for our application */ | |||
static struct CONTEXT_T { | |||
VCOS_SEMAPHORE_T semaphore; | |||
MMAL_QUEUE_T *queue; | |||
} context; | |||
/** Callback from the input port. | |||
* Buffer has been consumed and is available to be used again. */ | |||
static void input_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) | |||
{ | |||
struct CONTEXT_T *ctx = (struct CONTEXT_T *)port->userdata; | |||
/* The decoder is done with the data, just recycle the buffer header into its pool */ | |||
mmal_buffer_header_release(buffer); | |||
/* Kick the processing thread */ | |||
vcos_semaphore_post(&ctx->semaphore); | |||
} | |||
/** Callback from the output port. | |||
* Buffer has been produced by the port and is available for processing. */ | |||
static void output_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) | |||
{ | |||
struct CONTEXT_T *ctx = (struct CONTEXT_T *)port->userdata; | |||
/* Queue the decoded video frame */ | |||
mmal_queue_put(ctx->queue, buffer); | |||
/* Kick the processing thread */ | |||
vcos_semaphore_post(&ctx->semaphore); | |||
} | |||
int main(int argc, char **argv) | |||
{ | |||
MMAL_STATUS_T status = MMAL_EINVAL; | |||
MMAL_COMPONENT_T *decoder = 0; | |||
MMAL_POOL_T *pool_in = 0, *pool_out = 0; | |||
unsigned int count; | |||
if (argc < 2) | |||
{ | |||
fprintf(stderr, "invalid arguments\n"); | |||
return -1; | |||
} | |||
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; | |||
} |