mirror of
https://github.com/raspberrypi/userland.git
synced 2025-12-06 04:49:12 +00:00
Update master branch to next
This commit is contained in:
@@ -3,7 +3,11 @@ cmake_minimum_required(VERSION 2.8)
|
||||
project(vmcs_host_apps)
|
||||
|
||||
set(BUILD_MMAL TRUE)
|
||||
set(BUILD_MMAL_APPS FALSE)
|
||||
if (ALL_APPS)
|
||||
set(BUILD_MMAL_APPS TRUE)
|
||||
else()
|
||||
set(BUILD_MMAL_APPS FALSE)
|
||||
endif()
|
||||
set(vmcs_root ${PROJECT_SOURCE_DIR})
|
||||
get_filename_component(VIDEOCORE_ROOT . ABSOLUTE)
|
||||
|
||||
@@ -39,7 +43,7 @@ add_definitions(-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE)
|
||||
|
||||
# do we actually need this?
|
||||
add_definitions(-D__VIDEOCORE4__)
|
||||
|
||||
add_definitions(-DTV_SUPPORTED_MODE_NO_DEPRECATED)
|
||||
|
||||
# add_definitions(-DKHRONOS_CLIENT_LOGGING)
|
||||
|
||||
@@ -59,8 +63,10 @@ if(BUILD_MMAL)
|
||||
include_directories(interface/mmal)
|
||||
add_subdirectory(interface/mmal)
|
||||
endif()
|
||||
if(BUILD_MMAL_APPS)
|
||||
add_subdirectory(containers)
|
||||
endif()
|
||||
|
||||
#add_subdirectory(containers)
|
||||
add_subdirectory(middleware/openmaxil)
|
||||
|
||||
# 3d demo code
|
||||
@@ -84,7 +90,9 @@ add_subdirectory(interface/usbdk)
|
||||
|
||||
# VMCS Host Applications
|
||||
#add_subdirectory(host_applications/framework)
|
||||
#add_subdirectory(host_applications/vmcs)
|
||||
if(BUILD_MMAL_APPS)
|
||||
add_subdirectory(host_applications/vmcs)
|
||||
endif()
|
||||
|
||||
# add_subdirectory(interface/vchiq/test/win32)
|
||||
|
||||
@@ -95,6 +103,10 @@ add_subdirectory(interface/usbdk)
|
||||
# add linux apps
|
||||
add_subdirectory(host_applications/linux)
|
||||
|
||||
# Debug sym for mmal-vc-diag and vcdbg
|
||||
#add_subdirectory(host_applications/linux/libs/debug_sym)
|
||||
|
||||
|
||||
set(vmcs_host_apps_VERSION_MAJOR 1)
|
||||
set(vmcs_host_apps_VERSION_MINOR 0)
|
||||
|
||||
|
||||
@@ -45,8 +45,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#elif defined(__BCM2708B0__)
|
||||
/* 2708 b0 */
|
||||
#define V3D_REVISION 2
|
||||
#elif defined(__BCM2708C0__) || defined(__BCM2708C1__)
|
||||
/* 2708 c0/1 */
|
||||
#define V3D_REVISION 3
|
||||
#else
|
||||
/* fiji */
|
||||
/* capri */
|
||||
#define V3D_REVISION 6
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -55,6 +55,7 @@ typedef enum {
|
||||
METADATA_AGC_DEBUG = ('A'<<24)+('G'<<16)+('C'<<8)+('D'), // 'AGCD' struct ISP_TUNER_BRCM_AGC_DEBUG_T in /middleware/ISP/tuner/isp_tuner_agc.h
|
||||
METADATA_FOCUS_REGION = ('F'<<24)+('R'<<16)+('G'<<8)+('N'), // 'FRGN' struct ISP_TUNER_BRCM_AF_STATISTICS_PARAMS_T in /middleware/ISP/tuner/isp_tuner_brcm_common.h
|
||||
METADATA_FOCUS_WOI = ('F'<<24)+('W'<<16)+('O'<<8)+('I'), // 'FWOI' struct ISP_WOI_METADATA_T in /middleware/ISP/tuner/isp_tuner_ctrl.h
|
||||
METADATA_FOCUS_CAF = ('F'<<24)+('C'<<16)+('A'<<8)+('F'), // 'FCAF' struct ISP_CAF_METADATA_T in /middleware/ISP/tuner/isp_tuner_ctrl.h
|
||||
METADATA_AUTOFOCUS = ( 0 <<24)+( 0 <<16)+('A'<<8)+('F'), // '\x00\x00AF' struct ISP_AF_METADATA_T in /middleware/ISP/tuner/isp_tuner_ctrl.h
|
||||
METADATA_EV = ('E'<<24)+('V'<<16)+('M'<<8)+('D'), // 'EVMD' struct ISP_TUNER_BRCM_EV_METADATA_T in /middleware/ISP/tuner/isp_tuner_brcm_common.h
|
||||
METADATA_ISP = ('I'<<24)+('S'<<16)+('P'<<8)+('M'), // 'ISPM' struct ISP_ISP_METADATA_T in /middleware/ISP/tuner/isp_tuner_ctrl.h
|
||||
@@ -64,7 +65,8 @@ typedef enum {
|
||||
METADATA_SCENEDETECTION = ( 0 <<24)+('A'<<16)+('S'<<8)+('D'), // '\x00ASD' struct ASD_METADATA_T defined in /middleware/camplus/sw/asd_metadata.h
|
||||
METADATA_TUNER_SYNC = ('S'<<24)+('Y'<<16)+('N'<<8)+('C'), // 'SYNC' NULL data, just adds the item header.
|
||||
METADATA_DARK_FRAME_CORRECT = ('D'<<24)+('F'<<16)+('R'<<8)+('C'), // 'DFRC' 5 byte literal string "dfrc"
|
||||
METADATA_DARK_FRAME_SUB = ('D'<<24)+('F'<<16)+('S'<<8)+('B'), // 'DFSB' 3 byte literal string "on"
|
||||
METADATA_DARK_FRAME_SUB = ('D'<<24)+('F'<<16)+('S'<<8)+('B'), // 'DFSB' 3 byte literal string "on"
|
||||
METADATA_TUNER_DROP_FRAME = ('T'<<24)+('D'<<16)+('R'<<8)+('P'),
|
||||
METADATA_ABL = ( 0 <<24)+('A'<<16)+('B'<<8)+('L'), // '\x00ABL' struct ISP_TUNER_BRCM_BLACK_LEVEL_ABL_T defined in /middleware/ISP/tuner/isp_tuner_brcm_black_level.h
|
||||
METADATA_DRC = ( 0 <<24)+('D'<<16)+('R'<<8)+('C'), // 'DRC' struct DRC_METADATA_T defined in /middleware/camplus/sw/drc/drc.h
|
||||
METADATA_REGISTRATION = ( 0 <<24)+('R'<<16)+('E'<<8)+('G'), // 'REG' struct REGISTRATION_OFFSETS_T defined in /middleware/camplus/sw/registration/registration.h
|
||||
@@ -96,6 +98,10 @@ typedef enum {
|
||||
METADATA_ACUTE_AWB_LOG = ('A'<<24)+('E'<<16)+('L'<<8)+('C'), // 'AELC' : ISP_ACUTE_AWB_LOG
|
||||
METADATA_DF = ( 0 <<24)+( 0<<16)+('D'<<8)+('F'), // '\x00\x00DF' : DF_METADATA_T defined in /middleware/camplus/sw/df/df_metadata.h
|
||||
METADATA_MAGIC_MEASURE = ('S'<<24)+('S'<<16)+('M'<<8) + ('M'), // 'SSMM' : A statistic from the ISP used to determine the JPEG quality setting for a certain customer.
|
||||
METADATA_SNAPSHOT_JPEG_QUANTISER = ('S'<<24)+('S'<<16)+('J'<<8) + ('S'), // 'SSJQ' : The size of the snapshot frame when JPEG-encoded.
|
||||
|
||||
METADATA_SUPPLEMENTARY_INFO = ('S'<<24)+('U'<<16)+('P'<<8) + ('P'), // 'SUPP' : Supplimentary info defined in /codecs/video/hw/enc/venc_supplementary_info.h
|
||||
|
||||
METADATA_UNKNOWN = ('U'<<24)+('N'<<16)+('K'<<8)+('N') // 'UNKN'
|
||||
|
||||
} METADATA_CODE_T;
|
||||
|
||||
@@ -135,6 +135,7 @@ extern "C" {
|
||||
VC_IMAGE_YUVINFO_CSC_SMPTE_240M = 5, /* Society of Motion Picture and Television Engineers 240M (1999) */
|
||||
VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_M = 6, /* ITU-R BT.470-2 System M */
|
||||
VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_BG = 7, /* ITU-R BT.470-2 System B,G */
|
||||
VC_IMAGE_YUVINFO_CSC_JPEG_JFIF_Y16_255 = 8, /* JPEG JFIF, but with 16..255 luma */
|
||||
VC_IMAGE_YUVINFO_CSC_CUSTOM = 15, /* Custom colour matrix follows header */
|
||||
VC_IMAGE_YUVINFO_CSC_SMPTE_170M = VC_IMAGE_YUVINFO_CSC_ITUR_BT601,
|
||||
|
||||
@@ -157,7 +158,7 @@ extern "C" {
|
||||
bits should be zero and enforce this in vc_image functions to catch people
|
||||
who aren't initialising the VC_IMAGE_T structure nicely; update when other
|
||||
bits are added */
|
||||
#define VC_IMAGE_INFO_VALIDBITS 0x9F07
|
||||
#define VC_IMAGE_INFO_VALIDBITS 0x9F0F
|
||||
/* Define the bits of info used to denote the colourspace */
|
||||
#define VC_IMAGE_INFO_COLOURSPACE 0x0F
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ int main( int argc, char **argv )
|
||||
{
|
||||
int instNum = 0;
|
||||
VCHI_INSTANCE_T vchi_instance;
|
||||
VCHI_CONNECTION_T *vchi_connection;
|
||||
VCHI_CONNECTION_T *vchi_connection = NULL;
|
||||
|
||||
if ( argc > 1 )
|
||||
{
|
||||
@@ -73,32 +73,33 @@ int main( int argc, char **argv )
|
||||
{
|
||||
int i = 1;
|
||||
char buffer[ 1024 ];
|
||||
size_t buffer_offset = 0;
|
||||
clock_t before=0, after=0;
|
||||
double time_diff;
|
||||
uint32_t show_time = 0;
|
||||
int ret;
|
||||
|
||||
//reset the string
|
||||
strcpy( buffer, "" );
|
||||
buffer[0] = '\0';
|
||||
|
||||
//first, strip out a potential leading -t
|
||||
if( strcmp( argv[1], "-t" ) == 0 )
|
||||
{
|
||||
show_time = 1;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
for (; i <= argc-1; i++)
|
||||
{
|
||||
strcat( buffer, argv[i] );
|
||||
strcat( buffer, " " );
|
||||
buffer_offset = vcos_safe_strcpy( buffer, argv[i], sizeof(buffer), buffer_offset );
|
||||
buffer_offset = vcos_safe_strcpy( buffer, " ", sizeof(buffer), buffer_offset );
|
||||
}
|
||||
|
||||
if( show_time )
|
||||
before = clock();
|
||||
|
||||
//send the gencmd for the argument
|
||||
if (( ret = vc_gencmd_send( buffer )) != 0 )
|
||||
if (( ret = vc_gencmd_send( "%s", buffer )) != 0 )
|
||||
{
|
||||
printf( "vc_gencmd_send returned %d\n", ret );
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
set(EXEC hello_tiger.bin)
|
||||
set(SRCS tiger.c main.c)
|
||||
set(SRCS main.c tiger.c)
|
||||
add_definitions(-D__RASPBERRYPI__)
|
||||
|
||||
add_executable(${EXEC} ${SRCS})
|
||||
target_link_libraries(${EXEC} ${HELLO_PI_LIBS})
|
||||
|
||||
add_definitions(-D__RASPBERRYPI__)
|
||||
|
||||
install(TARGETS ${EXEC}
|
||||
RUNTIME DESTINATION bin)
|
||||
|
||||
@@ -39,6 +39,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "interface/vmcs_host/vc_tvservice.h"
|
||||
|
||||
#define TV_SUPPORTED_MODE_T TV_SUPPORTED_MODE_NEW_T
|
||||
#define vc_tv_hdmi_get_supported_modes vc_tv_hdmi_get_supported_modes_new
|
||||
#define vc_tv_hdmi_power_on_explicit vc_tv_hdmi_power_on_explicit_new
|
||||
|
||||
// ---- Public Variables ----------------------------------------------------
|
||||
|
||||
// ---- Private Constants and Types -----------------------------------------
|
||||
@@ -55,6 +59,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// Maximum length of option string (3 characters max for each option + NULL)
|
||||
#define OPTSTRING_LEN ( sizeof( long_opts ) / sizeof( *long_opts ) * 3 + 1 )
|
||||
|
||||
// Maximum mode ID
|
||||
#define MAX_MODE_ID (127)
|
||||
|
||||
// ---- Private Variables ---------------------------------------------------
|
||||
|
||||
enum
|
||||
@@ -101,11 +108,11 @@ static void show_usage( void )
|
||||
{
|
||||
LOG_STD( "Usage: tvservice [OPTION]..." );
|
||||
LOG_STD( " -p, --preferred Power on HDMI with preferred settings" );
|
||||
LOG_STD( " -e, --explicit=\"GROUP MODE\" Power on HDMI with explicit GROUP (CEA, DMT, CEA_3D)\n"
|
||||
LOG_STD( " -e, --explicit=\"GROUP MODE\" Power on HDMI with explicit GROUP (CEA, DMT, CEA_3D_SBS, CEA_3D_TAB)\n"
|
||||
" and MODE (see --modes)" );
|
||||
LOG_STD( " -n, --sdtvon=\"MODE ASPECT\" Power on SDTV with MODE (PAL or NTSC) and ASPECT (4:3 14:9 or 16:9)" );
|
||||
LOG_STD( " -o, --off Power off the display" );
|
||||
LOG_STD( " -m, --modes=GROUP Get supported modes for GROUP (CEA, DMT, CEA_3D)" );
|
||||
LOG_STD( " -m, --modes=GROUP Get supported modes for GROUP (CEA, DMT)" );
|
||||
LOG_STD( " -M, --monitor Monitor HDMI events" );
|
||||
LOG_STD( " -s, --status Get HDMI status" );
|
||||
LOG_STD( " -a, --audio Get supported audio information" );
|
||||
@@ -140,20 +147,85 @@ static void create_optstring( char *optstring )
|
||||
*short_opts++ = '\0';
|
||||
}
|
||||
|
||||
static int get_modes( HDMI_RES_GROUP_T group )
|
||||
/* Return the string presentation of aspect ratio */
|
||||
static const char *aspect_ratio_str(HDMI_ASPECT_T aspect_ratio) {
|
||||
switch(aspect_ratio) {
|
||||
case HDMI_ASPECT_4_3:
|
||||
return "4:3";
|
||||
case HDMI_ASPECT_14_9:
|
||||
return "14:9";
|
||||
case HDMI_ASPECT_16_9:
|
||||
return "16:9";
|
||||
case HDMI_ASPECT_5_4:
|
||||
return "5:4";
|
||||
case HDMI_ASPECT_16_10:
|
||||
return "16:10";
|
||||
case HDMI_ASPECT_15_9:
|
||||
return "15:9";
|
||||
case HDMI_ASPECT_64_27:
|
||||
return "64:27 (21:9)";
|
||||
default:
|
||||
return "unknown AR";
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the string presentation of aspect ratio */
|
||||
static const char *aspect_ratio_sd_str(SDTV_ASPECT_T aspect_ratio) {
|
||||
switch(aspect_ratio) {
|
||||
case SDTV_ASPECT_4_3:
|
||||
return "4:3";
|
||||
case SDTV_ASPECT_14_9:
|
||||
return "14:9";
|
||||
case SDTV_ASPECT_16_9:
|
||||
return "16:9";
|
||||
default:
|
||||
return "unknown AR";
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the string representation of 3D support bit mask */
|
||||
static const char* threed_str(uint32_t struct_3d_mask) {
|
||||
#define THREE_D_FORMAT_NAME_MAX_LEN 10 //Including the separator
|
||||
static const char* three_d_format_names[] = { //See HDMI_3D_STRUCT_T bit fields
|
||||
"FP", "F-Alt", "L-Alt", "SbS-Full",
|
||||
"Ldep", "Ldep+Gfx", "TopBot", "SbS-HH",
|
||||
"SbS-OLOR", "SbS-OLER", "SbS-ELOR", "SbS-ELER"
|
||||
};
|
||||
//Longest possible string is the concatenation of all of the above
|
||||
static char struct_desc[vcos_countof(three_d_format_names)*THREE_D_FORMAT_NAME_MAX_LEN+4] = {0};
|
||||
char *p = &struct_desc[0];
|
||||
char * const p_end = p + sizeof struct_desc;
|
||||
size_t j, added = 0;
|
||||
p += snprintf(p, p_end - p, "3D:");
|
||||
if(struct_3d_mask) {
|
||||
for(j = 0; j < vcos_countof(three_d_format_names); j++) {
|
||||
if(struct_3d_mask & (1 << j)) {
|
||||
p += snprintf(p, p_end - p, "%s|", three_d_format_names[j]);
|
||||
added++;
|
||||
}
|
||||
}
|
||||
if(added > 0)
|
||||
*(--p) = '\0'; //Get rid of final "|"
|
||||
}
|
||||
if(!added)
|
||||
p += snprintf(p, p_end - p, "none");
|
||||
|
||||
return struct_desc;
|
||||
}
|
||||
|
||||
static int get_modes( HDMI_RES_GROUP_T group)
|
||||
{
|
||||
TV_SUPPORTED_MODE_T supported_modes[TV_MAX_SUPPORTED_MODES];
|
||||
static TV_SUPPORTED_MODE_T supported_modes[MAX_MODE_ID] = {{0}};
|
||||
HDMI_RES_GROUP_T preferred_group;
|
||||
uint32_t preferred_mode;
|
||||
int num_modes;
|
||||
int i;
|
||||
|
||||
vcos_assert(( group == HDMI_RES_GROUP_CEA ) ||
|
||||
( group == HDMI_RES_GROUP_DMT ) ||
|
||||
( group == HDMI_RES_GROUP_CEA_3D ));
|
||||
( group == HDMI_RES_GROUP_DMT ));
|
||||
|
||||
num_modes = vc_tv_hdmi_get_supported_modes( group, supported_modes,
|
||||
TV_MAX_SUPPORTED_MODES,
|
||||
vcos_countof(supported_modes),
|
||||
&preferred_group,
|
||||
&preferred_mode );
|
||||
if ( num_modes < 0 )
|
||||
@@ -163,70 +235,172 @@ static int get_modes( HDMI_RES_GROUP_T group )
|
||||
}
|
||||
|
||||
LOG_STD( "Group %s has %u modes:",
|
||||
group == HDMI_RES_GROUP_CEA ? "CEA" : group == HDMI_RES_GROUP_DMT ? "DMT" : "CEA_3D", num_modes );
|
||||
HDMI_RES_GROUP_NAME(group), num_modes );
|
||||
for ( i = 0; i < num_modes; i++ )
|
||||
{
|
||||
LOG_STD( "%s mode %u: %ux%u @ %uHz, %s",
|
||||
char p[8] = {0};
|
||||
if( supported_modes[i].pixel_rep )
|
||||
snprintf(p, sizeof(p)-1, "x%d ", supported_modes[i].pixel_rep);
|
||||
else
|
||||
snprintf(p, sizeof(p)-1, " ");
|
||||
|
||||
LOG_STD( "%s mode %u: %ux%u @ %uHz %s, clock:%luMHz %s%s %s",
|
||||
supported_modes[i].native ? " (native)" : " ",
|
||||
supported_modes[i].code, supported_modes[i].width,
|
||||
supported_modes[i].height, supported_modes[i].frame_rate,
|
||||
supported_modes[i].scan_mode ? "interlaced" : "progressive" );
|
||||
aspect_ratio_str(supported_modes[i].aspect_ratio),
|
||||
supported_modes[i].pixel_freq / 1000000UL, p,
|
||||
supported_modes[i].scan_mode ? "interlaced" : "progressive",
|
||||
supported_modes[i].struct_3d_mask ? threed_str(supported_modes[i].struct_3d_mask) : "");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *status_mode( TV_DISPLAY_STATE_T *tvstate ) {
|
||||
static char mode_str[96] = {0};
|
||||
char *s = &mode_str[0];
|
||||
int chars_left = sizeof(mode_str) - 1, tmp = 0;
|
||||
if(tvstate->state & ( VC_HDMI_HDMI | VC_HDMI_DVI )) {
|
||||
//HDMI or DVI on
|
||||
if(tvstate->state & VC_HDMI_HDMI) {
|
||||
tmp = snprintf(s, chars_left, "HDMI");
|
||||
chars_left -= tmp; s += tmp;
|
||||
switch(tvstate->display.hdmi.group) {
|
||||
case HDMI_RES_GROUP_CEA:
|
||||
tmp = snprintf(s, chars_left, " CEA (%d)", tvstate->display.hdmi.mode); break;
|
||||
case HDMI_RES_GROUP_DMT:
|
||||
tmp = snprintf(s, chars_left, " DMT (%d)", tvstate->display.hdmi.mode); break;
|
||||
default:
|
||||
tmp = 0;
|
||||
}
|
||||
chars_left -= tmp; s += tmp;
|
||||
|
||||
if(tvstate->display.hdmi.format_3d) {
|
||||
switch(tvstate->display.hdmi.format_3d) {
|
||||
case HDMI_3D_FORMAT_SBS_HALF:
|
||||
tmp = snprintf(s, chars_left, " 3D SbS"); break;
|
||||
case HDMI_3D_FORMAT_TB_HALF:
|
||||
tmp = snprintf(s, chars_left, " 3D T&B"); break;
|
||||
default:
|
||||
tmp = 0; break;
|
||||
}
|
||||
chars_left -= tmp; s += tmp;
|
||||
}
|
||||
|
||||
//Only HDMI mode can signal pixel encoding in AVI infoframe
|
||||
switch(tvstate->display.hdmi.pixel_encoding) {
|
||||
case HDMI_PIXEL_ENCODING_RGB_LIMITED:
|
||||
tmp = snprintf(s, chars_left, " RGB lim"); break;
|
||||
case HDMI_PIXEL_ENCODING_RGB_FULL:
|
||||
tmp = snprintf(s, chars_left, " RGB full"); break;
|
||||
case HDMI_PIXEL_ENCODING_YCbCr444_LIMITED:
|
||||
tmp = snprintf(s, chars_left, " YCbCr444 lim"); break;
|
||||
case HDMI_PIXEL_ENCODING_YCbCr444_FULL:
|
||||
tmp = snprintf(s, chars_left, " YCbCr444 full"); break;
|
||||
case HDMI_PIXEL_ENCODING_YCbCr422_LIMITED:
|
||||
tmp = snprintf(s, chars_left, " YCbCr422 lim"); break;
|
||||
case HDMI_PIXEL_ENCODING_YCbCr422_FULL:
|
||||
tmp = snprintf(s, chars_left, " YCbCr422 full"); break;
|
||||
default:
|
||||
tmp = 0; break;
|
||||
}
|
||||
chars_left -= tmp; s += tmp;
|
||||
|
||||
} else {
|
||||
//DVI will always be RGB, and CEA mode will have limited range, DMT mode full range
|
||||
tmp = snprintf(s, chars_left, "DVI %s",
|
||||
(tvstate->display.hdmi.group == HDMI_RES_GROUP_CEA)?
|
||||
" RGB lim" : " RGB full");
|
||||
chars_left -= tmp; s += tmp;
|
||||
}
|
||||
|
||||
//This is the format's aspect ratio, not the one
|
||||
//signaled in the AVI infoframe
|
||||
tmp = snprintf(s, chars_left, " %s", aspect_ratio_str(tvstate->display.hdmi.aspect_ratio));
|
||||
chars_left -= tmp; s += tmp;
|
||||
|
||||
if(tvstate->display.hdmi.pixel_rep) {
|
||||
tmp = snprintf(s, chars_left, " x%d", tvstate->display.hdmi.pixel_rep);
|
||||
chars_left -= tmp; s += tmp;
|
||||
}
|
||||
|
||||
if(tvstate->state & VC_HDMI_HDCP_AUTH) {
|
||||
tmp = snprintf(s, chars_left, " HDCP");
|
||||
chars_left -= tmp; s += tmp;
|
||||
}
|
||||
} else if(tvstate->state & ( VC_SDTV_NTSC | VC_SDTV_PAL )) {
|
||||
if(tvstate->state & VC_SDTV_NTSC) {
|
||||
tmp = snprintf(s, chars_left, "NTSC");
|
||||
chars_left -= tmp; s += tmp;
|
||||
} else {
|
||||
tmp = snprintf(s, chars_left, "PAL");
|
||||
chars_left -= tmp; s += tmp;
|
||||
}
|
||||
|
||||
if(tvstate->display.sdtv.cp_mode) {
|
||||
switch(tvstate->display.sdtv.cp_mode) {
|
||||
case SDTV_CP_MACROVISION_TYPE1:
|
||||
tmp = snprintf(s, chars_left, " Macrovision type 1"); break;
|
||||
case SDTV_CP_MACROVISION_TYPE2:
|
||||
tmp = snprintf(s, chars_left, " Macrovision type 2"); break;
|
||||
case SDTV_CP_MACROVISION_TYPE3:
|
||||
tmp = snprintf(s, chars_left, " Macrovision type 3"); break;
|
||||
case SDTV_CP_MACROVISION_TEST1:
|
||||
tmp = snprintf(s, chars_left, " Macrovision test 1"); break;
|
||||
case SDTV_CP_MACROVISION_TEST2:
|
||||
tmp = snprintf(s, chars_left, " Macrovision test 2"); break;
|
||||
case SDTV_CP_CGMS_COPYFREE:
|
||||
tmp = snprintf(s, chars_left, " CGMS copy free"); break;
|
||||
case SDTV_CP_CGMS_COPYNOMORE:
|
||||
tmp = snprintf(s, chars_left, " CGMS copy no more"); break;
|
||||
case SDTV_CP_CGMS_COPYONCE:
|
||||
tmp = snprintf(s, chars_left, " CGMS copy once"); break;
|
||||
case SDTV_CP_CGMS_COPYNEVER:
|
||||
tmp = snprintf(s, chars_left, " CGMS copy never"); break;
|
||||
case SDTV_CP_WSS_COPYFREE:
|
||||
tmp = snprintf(s, chars_left, " WSS copy free"); break;
|
||||
case SDTV_CP_WSS_COPYRIGHT_COPYFREE:
|
||||
tmp = snprintf(s, chars_left, " WSS (c) copy free"); break;
|
||||
case SDTV_CP_WSS_NOCOPY:
|
||||
tmp = snprintf(s, chars_left, " WSS no copy"); break;
|
||||
case SDTV_CP_WSS_COPYRIGHT_NOCOPY:
|
||||
tmp = snprintf(s, chars_left, " WSS (c) no copy"); break;
|
||||
default:
|
||||
tmp = 0; break;
|
||||
}
|
||||
chars_left -= tmp; s += tmp;
|
||||
}
|
||||
//This is the format's aspect ratio
|
||||
tmp = snprintf(s, chars_left, " %s", aspect_ratio_str(tvstate->display.sdtv.display_options.aspect));
|
||||
chars_left -= tmp; s += tmp;
|
||||
} else {
|
||||
tmp = snprintf(s, chars_left, "TV is off");
|
||||
chars_left -= tmp; s += tmp;
|
||||
}
|
||||
|
||||
return mode_str;
|
||||
}
|
||||
|
||||
static int get_status( void )
|
||||
{
|
||||
TV_GET_STATE_RESP_T tvstate = {0};
|
||||
static const char *status_str[] = {
|
||||
"HPD low",
|
||||
"HPD high",
|
||||
"DVI mode",
|
||||
"HDMI mode",
|
||||
"HDCP off",
|
||||
"HDCP on",
|
||||
"", "", "", "", "", "", "", "", "", "", //end of HDMI states
|
||||
"", "", //Currently we don't have a way to detect these
|
||||
"NTSC mode", "PAL mode",
|
||||
"composite CP off", "composite CP on",
|
||||
"", "", "", "", "", "", "", "", "", ""
|
||||
};
|
||||
static char status[256] = {0};
|
||||
char *s = &status[0];
|
||||
int i;
|
||||
|
||||
vc_tv_get_state( &tvstate );
|
||||
for(i = 0; i < 16; i++) {
|
||||
if(tvstate.state & (1 << i)) {
|
||||
s += sprintf(s, "%s|", status_str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if((tvstate.state & (VC_HDMI_DVI|VC_HDMI_HDMI)) == 0)
|
||||
s += sprintf(s, "HDMI off|");
|
||||
|
||||
if(tvstate.state & (VC_SDTV_NTSC|VC_SDTV_PAL)) {
|
||||
for(i = 18; i < 31; i++) {
|
||||
if(tvstate.state & (1 << i)) {
|
||||
s += sprintf(s, "%s|", status_str[i]);
|
||||
}
|
||||
TV_DISPLAY_STATE_T tvstate;
|
||||
if( vc_tv_get_display_state( &tvstate ) == 0) {
|
||||
//The width/height parameters are in the same position in the union
|
||||
//for HDMI and SDTV
|
||||
if(tvstate.display.hdmi.width && tvstate.display.hdmi.height) {
|
||||
LOG_STD( "state 0x%x [%s], %ux%u @ %uHz, %s", tvstate.state,
|
||||
status_mode(&tvstate),
|
||||
tvstate.display.hdmi.width, tvstate.display.hdmi.height,
|
||||
tvstate.display.hdmi.frame_rate,
|
||||
tvstate.display.hdmi.scan_mode ? "interlaced" : "progressive" );
|
||||
} else {
|
||||
LOG_STD( "state 0x%x [%s]", tvstate.state, status_mode(&tvstate));
|
||||
}
|
||||
} else {
|
||||
s += sprintf(s, "composite off|");
|
||||
LOG_STD( "Error getting current display state");
|
||||
}
|
||||
|
||||
*(--s) = '\0';
|
||||
|
||||
if(tvstate.width && tvstate.height) {
|
||||
LOG_STD( "state: %s (0x%x), %ux%u @ %uHz, %s", status, tvstate.state,
|
||||
tvstate.width, tvstate.height, tvstate.frame_rate,
|
||||
tvstate.scan_mode ? "interlaced" : "progressive" );
|
||||
} else {
|
||||
LOG_STD( "state: %s (0x%x), HDMI powered off", status, tvstate.state);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_audiosup( void )
|
||||
@@ -267,7 +441,8 @@ static int get_audiosup( void )
|
||||
static int dump_edid( const char *filename )
|
||||
{
|
||||
uint8_t buffer[128];
|
||||
int written = 0, offset = 0, i, extensions = 0;
|
||||
size_t written = 0, offset = 0;
|
||||
int i, extensions = 0;
|
||||
FILE *fp = fopen(filename, "wb");
|
||||
int siz = vc_tv_hdmi_ddc_read(offset, sizeof (buffer), buffer);
|
||||
offset += sizeof( buffer);
|
||||
@@ -402,18 +577,34 @@ static int power_on_explicit( HDMI_RES_GROUP_T group,
|
||||
int ret;
|
||||
|
||||
LOG_STD( "Powering on HDMI with explicit settings (%s mode %u)",
|
||||
group == HDMI_RES_GROUP_CEA ? "CEA" : group == HDMI_RES_GROUP_DMT ? "DMT" : "CEA_3D", mode );
|
||||
group == HDMI_RES_GROUP_CEA ? "CEA" : group == HDMI_RES_GROUP_DMT ? "DMT" : "CUSTOM", mode );
|
||||
|
||||
ret = vc_tv_hdmi_power_on_explicit( HDMI_MODE_HDMI, group, mode );
|
||||
if ( ret != 0 )
|
||||
{
|
||||
LOG_ERR( "Failed to power on HDMI with explicit settings (%s mode %u)",
|
||||
group == HDMI_RES_GROUP_CEA ? "CEA" : group == HDMI_RES_GROUP_DMT ? "DMT" : "CEA_3D", mode );
|
||||
group == HDMI_RES_GROUP_CEA ? "CEA" : group == HDMI_RES_GROUP_DMT ? "DMT" : "CUSTOM", mode );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_property(HDMI_PROPERTY_T prop, uint32_t param1, uint32_t param2)
|
||||
{
|
||||
int ret;
|
||||
HDMI_PROPERTY_PARAM_T property;
|
||||
property.property = prop;
|
||||
property.param1 = param1;
|
||||
property.param2 = param2;
|
||||
LOG_STD( "Setting property %d with params %d, %d", prop, param1, param2);
|
||||
ret = vc_tv_hdmi_set_property(&property);
|
||||
if(ret != 0)
|
||||
{
|
||||
LOG_ERR( "Failed to set property %d", prop);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int power_on_sdtv( SDTV_MODE_T mode,
|
||||
SDTV_ASPECT_T aspect )
|
||||
{
|
||||
@@ -466,6 +657,7 @@ int main( int argc, char **argv )
|
||||
int opt_audiosup = 0;
|
||||
int opt_dumpedid = 0;
|
||||
int opt_showinfo = 0;
|
||||
int opt_3d = 0;
|
||||
char *dumpedid_filename = NULL;
|
||||
VCHI_INSTANCE_T vchi_instance;
|
||||
VCHI_CONNECTION_T *vchi_connection;
|
||||
@@ -501,7 +693,8 @@ int main( int argc, char **argv )
|
||||
{
|
||||
char group_str[32];
|
||||
|
||||
if ( sscanf( optarg, "%s %u", group_str,
|
||||
/* coverity[secure_coding] String length specified, so can't overflow */
|
||||
if ( sscanf( optarg, "%31s %u", group_str,
|
||||
&power_on_explicit_mode ) != 2 )
|
||||
{
|
||||
LOG_ERR( "Invalid arguments '%s'", optarg );
|
||||
@@ -517,9 +710,16 @@ int main( int argc, char **argv )
|
||||
{
|
||||
power_on_explicit_group = HDMI_RES_GROUP_DMT;
|
||||
}
|
||||
else if ( vcos_strcasecmp( "CEA_3D", group_str ) == 0 )
|
||||
else if ( vcos_strcasecmp( "CEA_3D", group_str ) == 0 ||
|
||||
vcos_strcasecmp( "CEA_3D_SBS", group_str ) == 0)
|
||||
{
|
||||
power_on_explicit_group = HDMI_RES_GROUP_CEA_3D;
|
||||
power_on_explicit_group = HDMI_RES_GROUP_CEA;
|
||||
opt_3d = 1;
|
||||
}
|
||||
else if ( vcos_strcasecmp( "CEA_3D_TAB", group_str ) == 0 )
|
||||
{
|
||||
power_on_explicit_group = HDMI_RES_GROUP_CEA;
|
||||
opt_3d = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -528,7 +728,7 @@ int main( int argc, char **argv )
|
||||
}
|
||||
|
||||
// Then check if mode is a sane number
|
||||
if ( power_on_explicit_mode > 256 )
|
||||
if ( power_on_explicit_mode > MAX_MODE_ID )
|
||||
{
|
||||
LOG_ERR( "Invalid mode '%u'", power_on_explicit_mode );
|
||||
goto err_out;
|
||||
@@ -602,10 +802,6 @@ int main( int argc, char **argv )
|
||||
{
|
||||
get_modes_group = HDMI_RES_GROUP_DMT;
|
||||
}
|
||||
else if ( vcos_strcasecmp( "CEA_3D", optarg ) == 0 )
|
||||
{
|
||||
get_modes_group = HDMI_RES_GROUP_CEA_3D;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERR( "Invalid group '%s'", optarg );
|
||||
@@ -644,6 +840,7 @@ int main( int argc, char **argv )
|
||||
default:
|
||||
{
|
||||
LOG_ERR( "Unrecognized option '%d'\n", opt );
|
||||
goto err_usage;
|
||||
}
|
||||
case '?':
|
||||
case OPT_HELP:
|
||||
@@ -710,7 +907,7 @@ int main( int argc, char **argv )
|
||||
|
||||
if ( opt_modes == 1 )
|
||||
{
|
||||
if ( get_modes( get_modes_group ) != 0 )
|
||||
if ( get_modes( get_modes_group) != 0 )
|
||||
{
|
||||
goto err_stop_service;
|
||||
}
|
||||
@@ -725,6 +922,16 @@ int main( int argc, char **argv )
|
||||
}
|
||||
else if ( opt_explicit == 1 )
|
||||
{
|
||||
//Distinguish between turning on 3D side by side and 3D top/bottom
|
||||
if(opt_3d == 1 && set_property( HDMI_PROPERTY_3D_STRUCTURE, HDMI_3D_FORMAT_SBS_HALF, 0) != 0)
|
||||
{
|
||||
goto err_stop_service;
|
||||
}
|
||||
else if(opt_3d == 2 && set_property( HDMI_PROPERTY_3D_STRUCTURE, HDMI_3D_FORMAT_TB_HALF, 0) != 0)
|
||||
{
|
||||
goto err_stop_service;
|
||||
}
|
||||
|
||||
if ( power_on_explicit( power_on_explicit_group,
|
||||
power_on_explicit_mode ) != 0 )
|
||||
{
|
||||
|
||||
@@ -43,6 +43,10 @@ typedef struct
|
||||
|
||||
} VC_DEBUG_SYMBOL_T;
|
||||
|
||||
/*
|
||||
* Debug header+params are constructed by makefiles/internals/memorymap.mk
|
||||
* (first .text section) and stored in the VC binary
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t symbolTableOffset;
|
||||
@@ -52,7 +56,7 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t vcMemBase;
|
||||
uint32_t vcMemBase; /* base address of loaded binary */
|
||||
uint32_t vcMemSize;
|
||||
uint32_t vcEntryPoint;
|
||||
uint32_t symbolTableLength;
|
||||
@@ -63,7 +67,7 @@ typedef struct
|
||||
// Offset within the videocore memory map to get the address of the debug header.
|
||||
#define VC_DEBUG_HEADER_OFFSET 0x2800
|
||||
|
||||
#if defined( __VC4_BIG_ISLAND__ ) || defined (PLATFORM_RASPBERRYPI)
|
||||
#if (defined( __VC4_BIG_ISLAND__ ) || defined (PLATFORM_RASPBERRYPI)) && !defined( __COVERITY__ )
|
||||
|
||||
/* Use of the debug symbols only makes sense on machines which have
|
||||
* some type of shared memory architecture.
|
||||
@@ -75,9 +79,9 @@ typedef struct
|
||||
#endif
|
||||
|
||||
#if USE_VC_DEBUG_SYMS
|
||||
# define PRAGMA(foo) pragma foo
|
||||
# define VCDBG_PRAGMA(foo) pragma foo
|
||||
#else
|
||||
# define PRAGMA(foo)
|
||||
# define VCDBG_PRAGMA(foo)
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -87,9 +91,9 @@ typedef struct
|
||||
|
||||
#if USE_VC_DEBUG_SYMS
|
||||
#define VC_DEBUG_SYMBOL(name,label,addr,size) \
|
||||
PRAGMA( Data(LIT, ".init.vc_debug_sym" ); ) \
|
||||
VCDBG_PRAGMA( Data(LIT, ".init.vc_debug_sym" ); ) \
|
||||
static const VC_DEBUG_SYMBOL_T vc_sym_##name = { label, (uint32_t)addr, size }; \
|
||||
PRAGMA( Data )
|
||||
VCDBG_PRAGMA( Data )
|
||||
#else
|
||||
#define VC_DEBUG_SYMBOL(name,label,addr,size)
|
||||
#endif
|
||||
@@ -115,30 +119,34 @@ typedef struct
|
||||
*/
|
||||
|
||||
#define VC_DEBUG_DECLARE_UNCACHED_VAR(var_type,var_name,var_init) \
|
||||
PRAGMA( Data(".ucdata"); ) \
|
||||
VCDBG_PRAGMA( Data(".ucdata"); ) \
|
||||
var_type var_name = (var_init); \
|
||||
PRAGMA( Data(); ) \
|
||||
VCDBG_PRAGMA( Data(); ) \
|
||||
var_type *vc_var_ptr_##var_name = &var_name; \
|
||||
VC_DEBUG_VAR(var_name)
|
||||
|
||||
#define VC_DEBUG_EXTERN_UNCACHED_VAR(var_type,var_name) \
|
||||
extern var_type var_name; \
|
||||
static var_type *vc_var_ptr_##var_name = &var_name
|
||||
|
||||
#define VC_DEBUG_DECLARE_UNCACHED_STATIC_VAR(var_type,var_name,var_init) \
|
||||
PRAGMA( Data(".ucdata"); ) \
|
||||
VCDBG_PRAGMA( Data(".ucdata"); ) \
|
||||
static var_type var_name = (var_init); \
|
||||
PRAGMA( Data(); ) \
|
||||
VCDBG_PRAGMA( Data(); ) \
|
||||
static var_type *vc_var_ptr_##var_name = &var_name; \
|
||||
VC_DEBUG_VAR(var_name)
|
||||
|
||||
#define VC_DEBUG_DECLARE_UNCACHED_VAR_ZERO(var_type,var_name) \
|
||||
PRAGMA( Data(".ucdata"); ) \
|
||||
VCDBG_PRAGMA( Data(".ucdata"); ) \
|
||||
var_type var_name = {0}; \
|
||||
PRAGMA( Data(); ) \
|
||||
VCDBG_PRAGMA( Data(); ) \
|
||||
var_type *vc_var_ptr_##var_name = &var_name; \
|
||||
VC_DEBUG_VAR(var_name)
|
||||
|
||||
#define VC_DEBUG_DECLARE_UNCACHED_STATIC_VAR_ZERO(var_type,var_name) \
|
||||
PRAGMA( Data(".ucdata"); ) \
|
||||
VCDBG_PRAGMA( Data(".ucdata"); ) \
|
||||
static var_type var_name = {0}; \
|
||||
PRAGMA( Data(); ) \
|
||||
VCDBG_PRAGMA( Data(); ) \
|
||||
static var_type *vc_var_ptr_##var_name = &var_name; \
|
||||
VC_DEBUG_VAR(var_name)
|
||||
|
||||
@@ -160,9 +168,9 @@ typedef struct
|
||||
*/
|
||||
|
||||
#define VC_DEBUG_DECLARE_UNCACHED_STATIC_VAR_NO_PTR(var_type,var_name,var_init) \
|
||||
PRAGMA( Data(".init.ucdata"); ) \
|
||||
VCDBG_PRAGMA( Data(".init.ucdata"); ) \
|
||||
static var_type var_name = (var_init); \
|
||||
PRAGMA( Data(); ) \
|
||||
VCDBG_PRAGMA( Data(); ) \
|
||||
VC_DEBUG_VAR(var_name)
|
||||
|
||||
/* ---- Variable Externs ------------------------------------------------- */
|
||||
|
||||
@@ -33,6 +33,7 @@ extern "C" {
|
||||
|
||||
#include "helpers/v3d/v3d_ver.h"
|
||||
|
||||
#define VC_KHRN_VERSION 1
|
||||
//#define KHRN_NOT_REALLY_DUALCORE // Use dual core codebase but switch master thread to vpu1
|
||||
//#define KHRN_SIMPLE_MULTISAMPLE
|
||||
//#define USE_CTRL_FOR_DATA
|
||||
|
||||
@@ -188,9 +188,28 @@ void vc_vchi_khronos_init()
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (vchiq_open_service(khrn_vchiq_instance, FOURCC_KHAN, khan_callback, NULL, &vchiq_khan_service) != VCHIQ_SUCCESS ||
|
||||
vchiq_open_service(khrn_vchiq_instance, FOURCC_KHRN, khrn_callback, NULL, &vchiq_khrn_service) != VCHIQ_SUCCESS ||
|
||||
vchiq_open_service(khrn_vchiq_instance, FOURCC_KHHN, khhn_callback, NULL, &vchiq_khhn_service) != VCHIQ_SUCCESS)
|
||||
VCHIQ_STATUS_T khan_return, khrn_return, khhn_return;
|
||||
VCHIQ_SERVICE_PARAMS_T params;
|
||||
|
||||
params.userdata = NULL;
|
||||
params.version = VC_KHRN_VERSION;
|
||||
params.version_min = VC_KHRN_VERSION;
|
||||
|
||||
params.fourcc = FOURCC_KHAN;
|
||||
params.callback = khan_callback;
|
||||
khan_return = vchiq_open_service(khrn_vchiq_instance, ¶ms, &vchiq_khan_service);
|
||||
|
||||
params.fourcc = FOURCC_KHRN;
|
||||
params.callback = khrn_callback;
|
||||
khrn_return = vchiq_open_service(khrn_vchiq_instance, ¶ms, &vchiq_khrn_service);
|
||||
|
||||
params.fourcc = FOURCC_KHHN;
|
||||
params.callback = khhn_callback;
|
||||
khhn_return = vchiq_open_service(khrn_vchiq_instance, ¶ms, &vchiq_khhn_service);
|
||||
|
||||
if (khan_return != VCHIQ_SUCCESS ||
|
||||
khrn_return != VCHIQ_SUCCESS ||
|
||||
khhn_return != VCHIQ_SUCCESS)
|
||||
{
|
||||
vcos_log_error("* failed to add service - already in use?");
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -148,10 +148,12 @@ static WFC_WAITER_T *wfc_client_ipc_get_waiter(WFC_CLIENT_IPC_T *client)
|
||||
break;
|
||||
}
|
||||
|
||||
vcos_assert(i != WFC_CLIENT_IPC_MAX_WAITERS); /* If we get here, semaphore isn't working */
|
||||
|
||||
waiter = client->waitpool.waiters + i;
|
||||
waiter->inuse = 1;
|
||||
/* If this fails, the semaphore isn't working */
|
||||
if (vcos_verify(i != WFC_CLIENT_IPC_MAX_WAITERS))
|
||||
{
|
||||
waiter = client->waitpool.waiters + i;
|
||||
waiter->inuse = 1;
|
||||
}
|
||||
vcos_mutex_unlock(&client->lock);
|
||||
|
||||
return waiter;
|
||||
@@ -199,6 +201,7 @@ static VCHIQ_STATUS_T wfc_client_ipc_vchiq_callback(VCHIQ_REASON_T reason,
|
||||
/* Call the client function */
|
||||
(*cb_func)(callback_msg->callback_data.ptr);
|
||||
}
|
||||
vchiq_release_message(service, vchiq_header);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -228,12 +231,18 @@ static VCHIQ_STATUS_T wfc_client_ipc_vchiq_callback(VCHIQ_REASON_T reason,
|
||||
case VCHIQ_BULK_RECEIVE_ABORTED:
|
||||
case VCHIQ_BULK_TRANSMIT_ABORTED:
|
||||
{
|
||||
vcos_assert(!"bulk messages not used");
|
||||
vcos_assert_msg(0, "bulk messages not used");
|
||||
vchiq_release_message(service, vchiq_header);
|
||||
}
|
||||
break;
|
||||
case VCHIQ_SERVICE_OPENED:
|
||||
vcos_log_trace("%s: service %p opened", VCOS_FUNCTION, service);
|
||||
break;
|
||||
case VCHIQ_SERVICE_CLOSED:
|
||||
vcos_log_trace("%s: service %p closed", VCOS_FUNCTION, service);
|
||||
break;
|
||||
default:
|
||||
vcos_assert(!"unexpected message reason");
|
||||
vcos_assert_msg(0, "unexpected message reason");
|
||||
break;
|
||||
}
|
||||
return VCHIQ_SUCCESS;
|
||||
@@ -391,27 +400,15 @@ VCOS_STATUS_T wfc_client_ipc_init(void)
|
||||
vchiq_params.fourcc = WFC_IPC_CONTROL_FOURCC();
|
||||
vchiq_params.callback = wfc_client_ipc_vchiq_callback;
|
||||
vchiq_params.userdata = &wfc_client_ipc;
|
||||
vchiq_params.version = WFC_IPC_VER_MAJOR;
|
||||
vchiq_params.version = WFC_IPC_VER_CURRENT;
|
||||
vchiq_params.version_min = WFC_IPC_VER_MINIMUM;
|
||||
|
||||
vchiq_status = vchiq_open_service_params(wfc_client_ipc_vchiq_instance, &vchiq_params, &wfc_client_ipc.service);
|
||||
vchiq_status = vchiq_open_service(wfc_client_ipc_vchiq_instance, &vchiq_params, &wfc_client_ipc.service);
|
||||
if (vchiq_status != VCHIQ_SUCCESS)
|
||||
{
|
||||
vcos_log_error("%s: could not open vchiq service: %d", VCOS_FUNCTION, vchiq_status);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (wfc_client_ipc.service == NULL)
|
||||
{
|
||||
vcos_log_error("%s: vchiq service is NULL, but open returned VCHIQ_SUCCESS?", VCOS_FUNCTION);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (wfc_client_ipc.service == NULL)
|
||||
{
|
||||
vcos_log_error("%s: vchiq service is NULL, but open returned VCHIQ_SUCCESS?", VCOS_FUNCTION);
|
||||
goto error;
|
||||
}
|
||||
service_initialised = true;
|
||||
|
||||
status = wfc_client_ipc_create_waitpool(&wfc_client_ipc.waitpool);
|
||||
|
||||
@@ -172,30 +172,30 @@ void wfc_server_destroy_context(WFCContext context)
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
uint32_t wfc_server_compose_scene(WFCContext context, const WFC_SCENE_T *scene,
|
||||
WFC_CALLBACK_T scene_taken_cb, void *scene_taken_data)
|
||||
uint32_t wfc_server_commit_scene(WFCContext context, const WFC_SCENE_T *scene,
|
||||
uint32_t flags, WFC_CALLBACK_T scene_taken_cb, void *scene_taken_data)
|
||||
{
|
||||
WFC_IPC_MSG_COMPOSE_SCENE_T msg;
|
||||
WFC_IPC_MSG_COMMIT_SCENE_T msg;
|
||||
VCOS_STATUS_T status = VCOS_SUCCESS;
|
||||
uint32_t result = VCOS_ENOSYS;
|
||||
size_t result_len = sizeof(result);
|
||||
uint32_t i;
|
||||
|
||||
vcos_log_trace("%s: context 0x%x elements %u wait %d scene_taken_cb %p _data %p",
|
||||
VCOS_FUNCTION, context, scene->element_count, scene->wait, scene_taken_cb,
|
||||
scene_taken_data);
|
||||
vcos_log_trace("%s: context 0x%x commit %u elements %u flags 0x%x",
|
||||
VCOS_FUNCTION, context, scene->commit_count, scene->element_count, flags);
|
||||
for (i = 0; i < scene->element_count; i++)
|
||||
{
|
||||
vcos_log_trace("%s: element[%u] stream 0x%x", VCOS_FUNCTION, i, scene->elements[i].source_stream);
|
||||
}
|
||||
|
||||
msg.header.type = WFC_IPC_MSG_COMPOSE_SCENE;
|
||||
msg.header.type = WFC_IPC_MSG_COMMIT_SCENE;
|
||||
msg.context = context;
|
||||
msg.flags = flags;
|
||||
msg.scene_taken_cb.ptr = scene_taken_cb;
|
||||
msg.scene_taken_data.ptr = scene_taken_data;
|
||||
memcpy(&msg.scene, scene, sizeof(*scene));
|
||||
|
||||
if (scene->wait)
|
||||
if (flags & WFC_SERVER_COMMIT_WAIT)
|
||||
{
|
||||
/* Caller will wait for callback, call cannot fail */
|
||||
vcos_assert(scene_taken_cb != NULL);
|
||||
@@ -265,16 +265,18 @@ void wfc_server_set_deferral_stream(WFCContext context, WFCNativeStreamType stre
|
||||
|
||||
WFCNativeStreamType wfc_server_stream_create(WFCNativeStreamType stream, uint32_t flags, uint32_t pid_lo, uint32_t pid_hi)
|
||||
{
|
||||
WFC_IPC_MSG_SS_CREATE_T msg;
|
||||
WFC_IPC_MSG_SS_CREATE_INFO_T msg;
|
||||
VCOS_STATUS_T status;
|
||||
WFCNativeStreamType result = WFC_INVALID_HANDLE;
|
||||
size_t result_len = sizeof(result);
|
||||
|
||||
vcos_log_trace("%s: stream 0x%x flags 0x%x pid 0x%x%08x", VCOS_FUNCTION, stream, flags, pid_hi, pid_lo);
|
||||
|
||||
msg.header.type = WFC_IPC_MSG_SS_CREATE;
|
||||
msg.header.type = WFC_IPC_MSG_SS_CREATE_INFO;
|
||||
msg.stream = stream;
|
||||
msg.flags = flags;
|
||||
memset(&msg.info, 0, sizeof(msg.info));
|
||||
msg.info.size = sizeof(msg.info);
|
||||
msg.info.flags = flags;
|
||||
msg.pid_lo = pid_lo;
|
||||
msg.pid_hi = pid_hi;
|
||||
|
||||
@@ -290,13 +292,61 @@ WFCNativeStreamType wfc_server_stream_create(WFCNativeStreamType stream, uint32_
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void wfc_server_stream_destroy(WFCNativeStreamType stream)
|
||||
WFCNativeStreamType wfc_server_stream_create_info(WFCNativeStreamType stream, const WFC_STREAM_INFO_T *info, uint32_t pid_lo, uint32_t pid_hi)
|
||||
{
|
||||
WFC_IPC_MSG_SS_CREATE_INFO_T msg;
|
||||
uint32_t copy_size;
|
||||
VCOS_STATUS_T status;
|
||||
WFCNativeStreamType result = WFC_INVALID_HANDLE;
|
||||
size_t result_len = sizeof(result);
|
||||
|
||||
if (!info)
|
||||
{
|
||||
vcos_log_error("%s: NULL info pointer passed", VCOS_FUNCTION);
|
||||
return WFC_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (info->size < sizeof(uint32_t))
|
||||
{
|
||||
vcos_log_error("%s: invalid info pointer passed (size:%u)", VCOS_FUNCTION, info->size);
|
||||
return WFC_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
vcos_log_trace("%s: stream 0x%x flags 0x%x pid 0x%x%08x", VCOS_FUNCTION, stream, info->flags, pid_hi, pid_lo);
|
||||
|
||||
msg.header.type = WFC_IPC_MSG_SS_CREATE_INFO;
|
||||
msg.stream = stream;
|
||||
copy_size = vcos_min(info->size, sizeof(msg.info));
|
||||
memcpy(&msg.info, info, copy_size);
|
||||
msg.info.size = copy_size;
|
||||
msg.pid_lo = pid_lo;
|
||||
msg.pid_hi = pid_hi;
|
||||
|
||||
status = wfc_client_ipc_sendwait(&msg.header, sizeof(msg), &result, &result_len);
|
||||
|
||||
vcos_log_trace("%s: status 0x%x, result 0x%x", VCOS_FUNCTION, status, result);
|
||||
|
||||
if (status != VCOS_SUCCESS)
|
||||
result = WFC_INVALID_HANDLE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void wfc_server_stream_destroy(WFCNativeStreamType stream, uint32_t pid_lo, uint32_t pid_hi)
|
||||
{
|
||||
WFC_IPC_MSG_SS_DESTROY_T msg;
|
||||
VCOS_STATUS_T status;
|
||||
|
||||
vcos_log_trace("%s: stream 0x%x", VCOS_FUNCTION, stream);
|
||||
|
||||
status = wfc_client_server_api_send_stream(WFC_IPC_MSG_SS_DESTROY, stream);
|
||||
msg.header.type = WFC_IPC_MSG_SS_DESTROY;
|
||||
msg.stream = stream;
|
||||
msg.pid_lo = pid_lo;
|
||||
msg.pid_hi = pid_hi;
|
||||
|
||||
status = wfc_client_ipc_send(&msg.header, sizeof(msg));
|
||||
|
||||
vcos_assert(status == VCOS_SUCCESS);
|
||||
}
|
||||
@@ -333,8 +383,8 @@ uint32_t wfc_server_stream_get_rects(WFCNativeStreamType stream, int32_t rects[W
|
||||
size_t rects_len = sizeof(reply) - sizeof(WFC_IPC_MSG_HEADER_T);
|
||||
|
||||
vcos_log_trace("%s: stream 0x%x", VCOS_FUNCTION, stream);
|
||||
|
||||
status = wfc_client_server_api_sendwait_stream(WFC_IPC_MSG_SS_GET_RECTS, stream, &reply.header + 1, &rects_len);
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
status = wfc_client_server_api_sendwait_stream(WFC_IPC_MSG_SS_GET_RECTS, stream, &reply.result, &rects_len);
|
||||
|
||||
if (status == VCOS_SUCCESS)
|
||||
{
|
||||
@@ -342,7 +392,7 @@ uint32_t wfc_server_stream_get_rects(WFCNativeStreamType stream, int32_t rects[W
|
||||
|
||||
if (result == VCOS_SUCCESS)
|
||||
{
|
||||
memcpy(rects, reply.rects, sizeof(rects));
|
||||
memcpy(rects, reply.rects, WFC_SERVER_STREAM_RECTS_SIZE * sizeof(*rects));
|
||||
vcos_log_trace("%s: rects (%d,%d,%d,%d) (%d,%d,%d,%d)", VCOS_FUNCTION,
|
||||
rects[0], rects[1], rects[2], rects[3], rects[4], rects[5], rects[6], rects[7]);
|
||||
}
|
||||
@@ -409,16 +459,27 @@ bool wfc_server_stream_allocate_images(WFCNativeStreamType stream, uint32_t widt
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void wfc_server_stream_signal_eglimage_data(WFCNativeStreamType stream, EGLImageKHR image_handle)
|
||||
void wfc_server_stream_signal_eglimage_data(WFCNativeStreamType stream,
|
||||
uint32_t ustorage, uint32_t width, uint32_t height, uint32_t stride,
|
||||
uint32_t offset, uint32_t format, uint32_t flags, bool flip)
|
||||
{
|
||||
WFC_IPC_MSG_SS_SIGNAL_EGLIMAGE_DATA_T msg;
|
||||
VCOS_STATUS_T status;
|
||||
|
||||
vcos_log_trace("%s: stream 0x%x image 0x%x", VCOS_FUNCTION, stream, (unsigned int)image_handle);
|
||||
|
||||
memset(&msg, 0, sizeof msg);
|
||||
msg.header.type = WFC_IPC_MSG_SS_SIGNAL_EGLIMAGE_DATA;
|
||||
msg.stream = stream;
|
||||
msg.image_handle = image_handle;
|
||||
msg.ustorage = ustorage;
|
||||
msg.width = width;
|
||||
msg.height = height;
|
||||
msg.stride = stride;
|
||||
msg.offset = offset;
|
||||
msg.format = format;
|
||||
msg.flags = flags;
|
||||
msg.flip = flip;
|
||||
|
||||
vcos_log_trace("%s: stream 0x%x image storage 0x%x",
|
||||
VCOS_FUNCTION, stream, ustorage);
|
||||
|
||||
status = wfc_client_ipc_send(&msg.header, sizeof(msg));
|
||||
|
||||
@@ -446,13 +507,15 @@ void wfc_server_stream_signal_mm_image_data(WFCNativeStreamType stream, uint32_t
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void wfc_server_stream_signal_raw_pixels(WFCNativeStreamType stream,
|
||||
uint32_t handle, uint32_t format, uint32_t width, uint32_t height, uint32_t pitch)
|
||||
uint32_t handle, uint32_t format, uint32_t width, uint32_t height,
|
||||
uint32_t pitch, uint32_t vpitch)
|
||||
{
|
||||
WFC_IPC_MSG_SS_SIGNAL_RAW_PIXELS_T msg;
|
||||
VCOS_STATUS_T status;
|
||||
|
||||
vcos_log_trace("%s: stream 0x%x image 0x%x format 0x%x width %u height %u pitch %u",
|
||||
VCOS_FUNCTION, stream, handle, format, width, height, pitch);
|
||||
vcos_log_trace("%s: stream 0x%x image 0x%x format 0x%x width %u height %u"
|
||||
" pitch %u vpitch %u",
|
||||
VCOS_FUNCTION, stream, handle, format, width, height, pitch, vpitch);
|
||||
|
||||
msg.header.type = WFC_IPC_MSG_SS_SIGNAL_RAW_PIXELS;
|
||||
msg.stream = stream;
|
||||
@@ -461,6 +524,38 @@ void wfc_server_stream_signal_raw_pixels(WFCNativeStreamType stream,
|
||||
msg.width = width;
|
||||
msg.height = height;
|
||||
msg.pitch = pitch;
|
||||
msg.vpitch = vpitch;
|
||||
|
||||
status = wfc_client_ipc_send(&msg.header, sizeof(msg));
|
||||
vcos_assert(status == VCOS_SUCCESS);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
void wfc_server_stream_signal_image(WFCNativeStreamType stream,
|
||||
const WFC_STREAM_IMAGE_T *image)
|
||||
{
|
||||
WFC_IPC_MSG_SS_SIGNAL_IMAGE_T msg;
|
||||
VCOS_STATUS_T status;
|
||||
|
||||
vcos_log_trace("%s: stream 0x%x type 0x%x handle 0x%x "
|
||||
" format 0x%x protection 0x%x width %u height %u "
|
||||
" pitch %u vpitch %u",
|
||||
VCOS_FUNCTION, stream, image->type, image->handle,
|
||||
image->format, image->protection, image->width, image->height,
|
||||
image->pitch, image->vpitch);
|
||||
|
||||
msg.header.type = WFC_IPC_MSG_SS_SIGNAL_IMAGE;
|
||||
msg.stream = stream;
|
||||
if vcos_verify(image->length <= sizeof(msg.image))
|
||||
{
|
||||
msg.image = *image;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Client is newer than VC ? */
|
||||
memcpy(&msg.image, image, sizeof(msg.image));
|
||||
msg.image.length = sizeof(msg.image);
|
||||
}
|
||||
|
||||
status = wfc_client_ipc_send(&msg.header, sizeof(msg));
|
||||
|
||||
@@ -488,19 +583,75 @@ void wfc_server_stream_register(WFCNativeStreamType stream, uint32_t pid_lo, uin
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void wfc_server_stream_unregister(WFCNativeStreamType stream)
|
||||
void wfc_server_stream_unregister(WFCNativeStreamType stream, uint32_t pid_lo, uint32_t pid_hi)
|
||||
{
|
||||
WFC_IPC_MSG_SS_UNREGISTER_T msg;
|
||||
VCOS_STATUS_T status;
|
||||
|
||||
vcos_log_trace("%s: stream 0x%x", VCOS_FUNCTION, stream);
|
||||
vcos_log_trace("%s: stream 0x%x pid 0x%x%08x", VCOS_FUNCTION, stream, pid_hi, pid_lo);
|
||||
|
||||
status = wfc_client_server_api_send_stream(WFC_IPC_MSG_SS_UNREGISTER, stream);
|
||||
msg.header.type = WFC_IPC_MSG_SS_UNREGISTER;
|
||||
msg.stream = stream;
|
||||
msg.pid_lo = pid_lo;
|
||||
msg.pid_hi = pid_hi;
|
||||
|
||||
status = wfc_client_ipc_send(&msg.header, sizeof(msg));
|
||||
|
||||
vcos_assert(status == VCOS_SUCCESS);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
uint32_t wfc_server_stream_get_info(WFCNativeStreamType stream, WFC_STREAM_INFO_T *info)
|
||||
{
|
||||
uint32_t result;
|
||||
VCOS_STATUS_T status;
|
||||
WFC_IPC_MSG_SS_GET_INFO_T reply;
|
||||
size_t info_len = sizeof(reply) - sizeof(WFC_IPC_MSG_HEADER_T);
|
||||
|
||||
if (!info)
|
||||
{
|
||||
vcos_log_error("%s: NULL info pointer passed", VCOS_FUNCTION);
|
||||
return WFC_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (info->size < sizeof(uint32_t))
|
||||
{
|
||||
vcos_log_error("%s: invalid info pointer passed (size:%u)", VCOS_FUNCTION, info->size);
|
||||
return WFC_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
vcos_log_trace("%s: stream 0x%x", VCOS_FUNCTION, stream);
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
status = wfc_client_server_api_sendwait_stream(WFC_IPC_MSG_SS_GET_INFO, stream, &reply.result, &info_len);
|
||||
|
||||
if (status == VCOS_SUCCESS)
|
||||
{
|
||||
result = reply.result;
|
||||
|
||||
if (result == VCOS_SUCCESS)
|
||||
{
|
||||
uint32_t copy_size = vcos_min(info->size, reply.info.size);
|
||||
memcpy(info, &reply.info, copy_size);
|
||||
info->size = copy_size;
|
||||
vcos_log_trace("%s: copied %u bytes", VCOS_FUNCTION, copy_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
vcos_log_error("%s: result %d", VCOS_FUNCTION, result);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vcos_log_error("%s: send msg status %d", VCOS_FUNCTION, status);
|
||||
result = status;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void wfc_server_stream_on_image_available(WFCNativeStreamType stream, WFC_CALLBACK_T image_available_cb, void *image_available_data)
|
||||
{
|
||||
WFC_IPC_MSG_SS_ON_IMAGE_AVAILABLE_T msg;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -86,7 +86,9 @@ uint32_t wfc_stream_create_req_rect
|
||||
|
||||
//!@brief Indicate that a source or mask is now associated with this stream, or should
|
||||
//! now be removed from such an association.
|
||||
void wfc_stream_register_source_or_mask(WFCNativeStreamType stream, bool add_source_or_mask);
|
||||
//!
|
||||
//!@return True if successful, false if not (invalid handle).
|
||||
bool wfc_stream_register_source_or_mask(WFCNativeStreamType stream, bool add_source_or_mask);
|
||||
|
||||
//!@brief Suspend until buffer is available on the server (requires
|
||||
//! WFC_STREAM_FLAGS_ASYNC_SEM to have been specified on creation).
|
||||
@@ -118,9 +120,14 @@ void wfc_stream_register_off_screen(WFCNativeStreamType stream, bool used_for_of
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void wfc_stream_signal_eglimage_data(WFCNativeStreamType stream, EGLImageKHR im);
|
||||
void wfc_stream_signal_eglimage_data_protected(WFCNativeStreamType stream, EGLImageKHR im, uint32_t is_protected);
|
||||
void wfc_stream_release_eglimage_data(WFCNativeStreamType stream, EGLImageKHR im);
|
||||
void wfc_stream_signal_mm_image_data(WFCNativeStreamType stream, uint32_t im);
|
||||
|
||||
void wfc_stream_signal_raw_pixels(WFCNativeStreamType stream, uint32_t handle, uint32_t format, uint32_t w, uint32_t h, uint32_t pitch);
|
||||
void wfc_stream_signal_raw_pixels(WFCNativeStreamType stream, uint32_t handle,
|
||||
uint32_t format, uint32_t w, uint32_t h, uint32_t pitch, uint32_t vpitch);
|
||||
void wfc_stream_signal_image(WFCNativeStreamType stream,
|
||||
const WFC_STREAM_IMAGE_T *image);
|
||||
void wfc_stream_register(WFCNativeStreamType stream);
|
||||
void wfc_stream_unregister(WFCNativeStreamType stream);
|
||||
|
||||
|
||||
@@ -123,15 +123,82 @@ typedef struct
|
||||
//! Arbitrary maximum number of elements per scene
|
||||
#define WFC_MAX_ELEMENTS_IN_SCENE 8
|
||||
|
||||
//! Arbitrary maximum number of WFC stream ids per client
|
||||
#define WFC_MAX_STREAMS_PER_CLIENT 128
|
||||
|
||||
//! Data for a "scene" (i.e. context and element data associated with a commit).
|
||||
typedef struct
|
||||
{
|
||||
WFC_CONTEXT_DYNAMIC_ATTRIB_T context; //!< Dynamic attributes for this scene's context
|
||||
uint32_t wait; //!< When true, signal when scene has been sent to compositor
|
||||
uint32_t commit_count; //!< Count of the scenes committed for this context
|
||||
uint32_t element_count; //!< Number of elements to be committed
|
||||
WFC_ELEMENT_ATTRIB_T elements[WFC_MAX_ELEMENTS_IN_SCENE]; //!< Attributes of committed elements
|
||||
} WFC_SCENE_T;
|
||||
|
||||
//definitions moved from wfc_server_stream.h so can be included on client
|
||||
|
||||
typedef enum
|
||||
{
|
||||
WFC_IMAGE_NO_FLAGS = 0,
|
||||
WFC_IMAGE_FLIP_VERT = (1 << 0), //< Vertically flip image
|
||||
WFC_IMAGE_DISP_NOTHING = (1 << 1), //< Display nothing on screen
|
||||
WFC_IMAGE_CB_ON_NO_CHANGE = (1 << 2), //< Callback, even if the image is the same
|
||||
WFC_IMAGE_CB_ON_COMPOSE = (1 << 3), //< Callback on composition, instead of when not in use
|
||||
WFC_IMAGE_PROTECTION_HDCP = (1 << 4), //< HDCP required if output to HDMI display
|
||||
WFC_IMAGE_FLIP_HORZ = (1 << 5), //< Horizontally flip image
|
||||
WFC_IMAGE_SENTINEL = 0x7FFFFFFF
|
||||
} WFC_IMAGE_FLAGS_T;
|
||||
|
||||
//! Define the type of generic WFC image
|
||||
typedef enum
|
||||
{
|
||||
WFC_STREAM_IMAGE_TYPE_OPAQUE = 0, //< Handle to a multimedia opaque image
|
||||
WFC_STREAM_IMAGE_TYPE_RAW, //< Handle to a raw pixel buffer in shared memory
|
||||
WFC_STREAM_IMAGE_TYPE_EGL, //< Handle to an EGL storage
|
||||
|
||||
WFC_STREAM_IMAGE_TYPE_SENTINEL = 0x7FFFFFFF
|
||||
} WFC_STREAM_IMAGE_TYPE_T;
|
||||
|
||||
//! DRM protection attributes for an image. Currently tis just maps to
|
||||
//! WFC_IMAGE_PROTECTION_HDCP and DISPMANX_PROTECTION_HDCP but in future
|
||||
//! could contain other options e.g. to down-sample output.
|
||||
typedef enum
|
||||
{
|
||||
WFC_PROTECTION_NONE = 0, //< Image is unprotected
|
||||
WFC_PROTECTION_HDCP = (1 << 0), //< HDCP required if output to HDMI display
|
||||
|
||||
WFC_PROTECTION_SENTINEL = 0x7FFFFFFF
|
||||
} WFC_PROTECTION_FLAGS_T;
|
||||
|
||||
//! Horizontal and vertical flip combinations
|
||||
typedef enum
|
||||
{
|
||||
WFC_STREAM_IMAGE_FLIP_NONE = 0, //< No flip
|
||||
WFC_STREAM_IMAGE_FLIP_VERT, //< Vertical flip only
|
||||
WFC_STREAM_IMAGE_FLIP_HORZ, //< Horizontal flip only
|
||||
WFC_STREAM_IMAGE_FLIP_BOTH, //< Horizontal and vertical flip (180 degree rotation)
|
||||
|
||||
WFC_STREAM_IMAGE_FLIP_SENTINEL = 0x7FFFFFFF
|
||||
} WFC_STREAM_IMAGE_FLIP_T;
|
||||
|
||||
//! Describes a generic buffer on the reloctable heap.
|
||||
typedef struct
|
||||
{
|
||||
uint32_t length; //< The size of the structure passed in the message. Used for versioning.
|
||||
WFC_STREAM_IMAGE_TYPE_T type; //< The type of the image buffer e.g. opaque.
|
||||
uint32_t handle; //< The relocatable heap handle for the buffer
|
||||
uint32_t width; //< Width of the image in pixels
|
||||
uint32_t height; //< Height of the image in pixels
|
||||
uint32_t format; //< The pixel format. Specific to type.
|
||||
uint32_t pitch; //< The horizontal pitch of the image in bytes
|
||||
uint32_t vpitch; //< The vertical pitch of the image in rows. Zero implies vpitch == height
|
||||
WFC_PROTECTION_FLAGS_T protection; //< DRM protection
|
||||
uint32_t offset; //< The starting offset within the heap handle for the buffer
|
||||
uint32_t flags; //< Type-specific flags associated with the buffer
|
||||
WFC_STREAM_IMAGE_FLIP_T flip; //< Flips to apply to the buffer for display
|
||||
} WFC_STREAM_IMAGE_T;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
// VideoCore-specific definitions
|
||||
//==============================================================================
|
||||
@@ -159,13 +226,28 @@ typedef enum
|
||||
{
|
||||
WFC_PIXEL_FORMAT_NONE,
|
||||
WFC_PIXEL_FORMAT_YVU420PLANAR,
|
||||
WFC_PIXEL_FORMAT_YUV420PLANAR,
|
||||
WFC_PIXEL_FORMAT_FORCE_32BIT = 0x7FFFFFFF
|
||||
} WFC_PIXEL_FORMAT_T;
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Non-standard functions
|
||||
|
||||
void wfc_set_deferral_stream(WFCDevice dev, WFCContext ctx, WFCNativeStreamType stream);
|
||||
|
||||
//==============================================================================
|
||||
|
||||
// Callback function types.
|
||||
|
||||
/** Called when the buffer of a stream is no longer in use.
|
||||
*
|
||||
* @param The client stream handle.
|
||||
* @param The value passed in when the buffer was set as the front buffer.
|
||||
*/
|
||||
typedef void (*WFC_SERVER_STREAM_CALLBACK_T)(WFCNativeStreamType stream, void *cb_data);
|
||||
|
||||
//==============================================================================
|
||||
|
||||
#endif /* WFC_INT_H */
|
||||
|
||||
@@ -36,13 +36,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#define WFC_IPC_CONTROL_FOURCC() VCHIQ_MAKE_FOURCC('W','F','C','I')
|
||||
|
||||
/* Major version indicates binary backwards compatiblity */
|
||||
#define WFC_IPC_VER_MAJOR 1
|
||||
/* Minor version is increased for new APIs where backwards
|
||||
* binary compatibility is retained for existing APIs */
|
||||
#define WFC_IPC_VER_MINOR 0
|
||||
/* Define the current version number of the IPC API that the host library of VC
|
||||
* server is built against.
|
||||
*/
|
||||
/* The current IPC version number */
|
||||
#define WFC_IPC_VER_CURRENT 8
|
||||
|
||||
/* The minimum verison number for backwards compatibility */
|
||||
#ifndef WFC_IPC_VER_MINIMUM
|
||||
#define WFC_IPC_VER_MINIMUM WFC_IPC_VER_MAJOR
|
||||
#define WFC_IPC_VER_MINIMUM 5
|
||||
#endif
|
||||
|
||||
/** Definitions of messages used for implementing the WFC API on the server.
|
||||
@@ -55,7 +57,7 @@ typedef enum {
|
||||
WFC_IPC_MSG_GET_VERSION, /**< Returns major, minor and minimum values */
|
||||
WFC_IPC_MSG_CREATE_CONTEXT, /**< Returns uint32_t */
|
||||
WFC_IPC_MSG_DESTROY_CONTEXT,
|
||||
WFC_IPC_MSG_COMPOSE_SCENE,
|
||||
WFC_IPC_MSG_COMMIT_SCENE,
|
||||
WFC_IPC_MSG_ACTIVATE,
|
||||
WFC_IPC_MSG_DEACTIVATE,
|
||||
WFC_IPC_MSG_SET_DEFERRAL_STREAM,
|
||||
@@ -71,11 +73,15 @@ typedef enum {
|
||||
WFC_IPC_MSG_SS_REGISTER,
|
||||
WFC_IPC_MSG_SS_UNREGISTER,
|
||||
WFC_IPC_MSG_SS_ON_IMAGE_AVAILABLE,
|
||||
WFC_IPC_MSG_SS_SIGNAL_IMAGE, /**< Signal to update the front buffer of a generic image stream */
|
||||
WFC_IPC_MSG_SS_CREATE_INFO, /**< Returns WFCNativeStreamType */
|
||||
WFC_IPC_MSG_SS_GET_INFO, /**< Get stream configuration information */
|
||||
|
||||
WFC_IPC_MSG_COUNT, /**< Always immediately after last client message type */
|
||||
|
||||
WFC_IPC_MSG_CALLBACK, /**< Sent from server to complete callback */
|
||||
|
||||
|
||||
WFC_IPC_MSG_MAX = 0x7FFFFFFF /**< Force type to be 32-bit */
|
||||
} WFC_IPC_MSG_TYPE;
|
||||
|
||||
@@ -160,8 +166,9 @@ typedef struct {
|
||||
WFC_IPC_CALLBACK_T scene_taken_cb; /**< Opaque client function pointer */
|
||||
WFC_IPC_VOID_PTR_T scene_taken_data; /**< Opaque client data */
|
||||
WFCContext context;
|
||||
uint32_t flags;
|
||||
WFC_SCENE_T scene;
|
||||
} WFC_IPC_MSG_COMPOSE_SCENE_T;
|
||||
} WFC_IPC_MSG_COMMIT_SCENE_T;
|
||||
|
||||
/** Set deferral stream message */
|
||||
typedef struct {
|
||||
@@ -181,6 +188,25 @@ typedef struct {
|
||||
uint32_t pid_hi;
|
||||
} WFC_IPC_MSG_SS_CREATE_T;
|
||||
|
||||
/** Create stream using info block message */
|
||||
typedef struct {
|
||||
WFC_IPC_MSG_HEADER_T header; /**< All messages start with a header */
|
||||
|
||||
WFCNativeStreamType stream;
|
||||
WFC_STREAM_INFO_T info;
|
||||
uint32_t pid_lo;
|
||||
uint32_t pid_hi;
|
||||
} WFC_IPC_MSG_SS_CREATE_INFO_T;
|
||||
|
||||
/** Destroy stream message */
|
||||
typedef struct {
|
||||
WFC_IPC_MSG_HEADER_T header; /**< All messages start with a header */
|
||||
|
||||
WFCNativeStreamType stream;
|
||||
uint32_t pid_lo;
|
||||
uint32_t pid_hi;
|
||||
} WFC_IPC_MSG_SS_DESTROY_T;
|
||||
|
||||
/** Set stream rectangle update callback message */
|
||||
typedef struct {
|
||||
WFC_IPC_MSG_HEADER_T header; /**< All messages start with a header */
|
||||
@@ -213,7 +239,14 @@ typedef struct {
|
||||
WFC_IPC_MSG_HEADER_T header; /**< All messages start with a header */
|
||||
|
||||
WFCNativeStreamType stream;
|
||||
EGLImageKHR image_handle;
|
||||
uint32_t ustorage;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t stride;
|
||||
uint32_t offset;
|
||||
uint32_t format;
|
||||
uint32_t flags;
|
||||
bool flip;
|
||||
} WFC_IPC_MSG_SS_SIGNAL_EGLIMAGE_DATA_T;
|
||||
|
||||
/** Signal new multimedia image message */
|
||||
@@ -234,8 +267,20 @@ typedef struct {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t pitch;
|
||||
uint32_t vpitch;
|
||||
} WFC_IPC_MSG_SS_SIGNAL_RAW_PIXELS_T;
|
||||
|
||||
/** Signals a new image buffer */
|
||||
typedef struct {
|
||||
WFC_IPC_MSG_HEADER_T header; /**< All messages start with a header */
|
||||
WFCNativeStreamType stream;
|
||||
|
||||
/**< Descibes the image buffer.
|
||||
* image.length initialised to sizeof(WFC_STREAM_IMAGE_T) */
|
||||
WFC_STREAM_IMAGE_T image;
|
||||
|
||||
} WFC_IPC_MSG_SS_SIGNAL_IMAGE_T;
|
||||
|
||||
/** Register stream as owned by process message */
|
||||
typedef struct {
|
||||
WFC_IPC_MSG_HEADER_T header; /**< All messages start with a header */
|
||||
@@ -245,6 +290,22 @@ typedef struct {
|
||||
uint32_t pid_hi;
|
||||
} WFC_IPC_MSG_SS_REGISTER_T;
|
||||
|
||||
/** Unregister stream as owned by process message */
|
||||
typedef struct {
|
||||
WFC_IPC_MSG_HEADER_T header; /**< All messages start with a header */
|
||||
|
||||
WFCNativeStreamType stream;
|
||||
uint32_t pid_lo;
|
||||
uint32_t pid_hi;
|
||||
} WFC_IPC_MSG_SS_UNREGISTER_T;
|
||||
|
||||
typedef struct {
|
||||
WFC_IPC_MSG_HEADER_T header; /**< All messages start with a header */
|
||||
|
||||
uint32_t result;
|
||||
WFC_STREAM_INFO_T info;
|
||||
} WFC_IPC_MSG_SS_GET_INFO_T;
|
||||
|
||||
/** Set stream image available callback message */
|
||||
typedef struct {
|
||||
WFC_IPC_MSG_HEADER_T header; /**< All messages start with a header */
|
||||
@@ -266,18 +327,22 @@ typedef union
|
||||
WFC_IPC_MSG_CONTEXT_T context;
|
||||
WFC_IPC_MSG_STREAM_T stream;
|
||||
WFC_IPC_MSG_CREATE_CONTEXT_T create_context;
|
||||
WFC_IPC_MSG_COMPOSE_SCENE_T compose_scene;
|
||||
WFC_IPC_MSG_COMMIT_SCENE_T commit_scene;
|
||||
WFC_IPC_MSG_SET_DEFERRAL_STREAM_T set_deferral_stream;
|
||||
WFC_IPC_MSG_SS_CREATE_T ss_create;
|
||||
WFC_IPC_MSG_SS_CREATE_INFO_T ss_create_info;
|
||||
WFC_IPC_MSG_SS_DESTROY_T ss_destroy;
|
||||
WFC_IPC_MSG_SS_ON_RECTS_CHANGE_T ss_on_rects_change;
|
||||
WFC_IPC_MSG_SS_ALLOCATE_IMAGES_T ss_allocate_images;
|
||||
WFC_IPC_MSG_SS_SIGNAL_EGLIMAGE_DATA_T ss_signal_eglimage_data;
|
||||
WFC_IPC_MSG_SS_SIGNAL_MM_IMAGE_DATA_T ss_signal_mm_image_data;
|
||||
WFC_IPC_MSG_SS_SIGNAL_RAW_PIXELS_T ss_signal_raw_image_data;
|
||||
WFC_IPC_MSG_SS_REGISTER_T ss_register;
|
||||
WFC_IPC_MSG_SS_UNREGISTER_T ss_unregister;
|
||||
WFC_IPC_MSG_SS_ON_IMAGE_AVAILABLE_T ss_on_image_available;
|
||||
WFC_IPC_MSG_GET_VERSION_T get_version;
|
||||
WFC_IPC_MSG_SS_GET_RECTS_T ss_get_rects;
|
||||
WFC_IPC_MSG_SS_SIGNAL_IMAGE_T ss_signal_image;
|
||||
} WFC_IPC_MSG_T;
|
||||
|
||||
#define WFC_IPC_MSG_MAGIC VCHIQ_MAKE_FOURCC('W', 'F', 'C', 'm')
|
||||
|
||||
@@ -46,6 +46,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
typedef void (*WFC_CALLBACK_T)(void *cb_data);
|
||||
|
||||
/** Extensible stream information block, supplied during creation and
|
||||
* retrievable using wfc_server_stream_get_info. */
|
||||
typedef struct WFC_STREAM_INFO_T
|
||||
{
|
||||
uint32_t size; /**< Size of the strucuture, for versioning. */
|
||||
uint32_t flags; /**< Stream flags. */
|
||||
} WFC_STREAM_INFO_T;
|
||||
|
||||
/** Create a connection to the server, as necessary. If this fails, no other
|
||||
* server functions should be called. If it succeeds, there must be one call to
|
||||
* wfc_server_disconnect() when use of the server has ended.
|
||||
@@ -90,19 +98,31 @@ uint32_t wfc_server_create_context(WFCContext context, uint32_t context_type,
|
||||
*/
|
||||
void wfc_server_destroy_context(WFCContext ctx);
|
||||
|
||||
/** Compose a scene in the context. This also updates the scene to be composed
|
||||
* automatically by an active context.
|
||||
/** Flags to be passed to wfc_server_commit_scene. A bitwise combination of
|
||||
* flags may be passed in to control behaviour.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
WFC_SERVER_COMMIT_WAIT = 1, /**< Wait for scene to be committed. */
|
||||
WFC_SERVER_COMMIT_COMPOSE = 2, /**< Trigger composition */
|
||||
} WFC_SERVER_COMMIT_FLAGS_T;
|
||||
|
||||
/** Commit a scene in the context. If the WAIT flag is set, a callback
|
||||
* must be given and shall be called once a new scene can be given. If the
|
||||
* COMPOSE flag is set, the newly committed scene shall be composed
|
||||
* as soon as possible (subject to presence of a deferral stream).
|
||||
*
|
||||
* @param context The client context identifier.
|
||||
* @param scene The scene to be composed.
|
||||
* @param flags Combination of WFC_SERVER_COMMIT_FLAGS_T values, or 0.
|
||||
* @param scene_taken_cb Called when scene has been taken, generally on a
|
||||
* different thread, or zero for no callback.
|
||||
* @param scene_taken_data Passed to scene_taken_cb.
|
||||
* @return VCOS_SUCCESS if successful, VCOS_EAGAIN if the scene cannot be
|
||||
* taken immediately and the wait field is false.
|
||||
* taken immediately and the wait flag is false.
|
||||
*/
|
||||
uint32_t wfc_server_compose_scene(WFCContext ctx, const WFC_SCENE_T *scene,
|
||||
WFC_CALLBACK_T scene_taken_cb, void *scene_taken_data);
|
||||
uint32_t wfc_server_commit_scene(WFCContext ctx, const WFC_SCENE_T *scene,
|
||||
uint32_t flags, WFC_CALLBACK_T scene_taken_cb, void *scene_taken_data);
|
||||
|
||||
/** Activate a context. While a context is active, it will be automatically
|
||||
* composed when any of the streams in its current scene are updated.
|
||||
@@ -138,11 +158,25 @@ void wfc_server_set_deferral_stream(WFCContext ctx, WFCNativeStreamType stream);
|
||||
WFCNativeStreamType wfc_server_stream_create(
|
||||
WFCNativeStreamType stream, uint32_t flags, uint32_t pid_lo, uint32_t pid_hi);
|
||||
|
||||
/** Create a stream and its buffers, for supplying pixel data to one or more
|
||||
* elements, and optionally for storing the output of off-screen composition.
|
||||
*
|
||||
* @param stream The client stream identifier.
|
||||
* @param info Stream configuration.
|
||||
* @param pid_lo The low 32-bits of the owning client process identifier.
|
||||
* @param pid_hi The high 32-bits of the owning client process identifier.
|
||||
* @return The client stream identifier on success, or WFC_INVALID_HANDLE on error.
|
||||
*/
|
||||
WFCNativeStreamType wfc_server_stream_create_info(
|
||||
WFCNativeStreamType stream, const WFC_STREAM_INFO_T *info, uint32_t pid_lo, uint32_t pid_hi);
|
||||
|
||||
/** Destroy a stream.
|
||||
*
|
||||
* @param stream The client stream identifier.
|
||||
* @param pid_lo The low 32-bits of the owning client process identifier.
|
||||
* @param pid_hi The high 32-bits of the owning client process identifier.
|
||||
*/
|
||||
void wfc_server_stream_destroy(WFCNativeStreamType stream);
|
||||
void wfc_server_stream_destroy(WFCNativeStreamType stream, uint32_t pid_lo, uint32_t pid_hi);
|
||||
|
||||
/** Set callback for when src/dest rectangles are updated.
|
||||
*
|
||||
@@ -183,11 +217,19 @@ bool wfc_server_stream_is_in_use(WFCNativeStreamType stream);
|
||||
bool wfc_server_stream_allocate_images(WFCNativeStreamType stream, uint32_t width, uint32_t height, uint32_t nbufs);
|
||||
|
||||
/** Signal that the given EGLImageKHR is the new front image for the stream.
|
||||
*
|
||||
* @param stream The client stream identifier.
|
||||
* @param image_handle The new front image for the stream.
|
||||
* @param stream The client stream identifier.
|
||||
* @param ustorage The innards of KHRN_IMAGE_T
|
||||
* @param width etc..
|
||||
* @param height etc...
|
||||
* @param stride
|
||||
* @param offset
|
||||
* @param format
|
||||
* @param flags
|
||||
* @param flip
|
||||
*/
|
||||
void wfc_server_stream_signal_eglimage_data(WFCNativeStreamType stream, EGLImageKHR image_handle);
|
||||
void wfc_server_stream_signal_eglimage_data(WFCNativeStreamType stream,
|
||||
uint32_t ustorage, uint32_t width, uint32_t height, uint32_t stride,
|
||||
uint32_t offset, uint32_t format, uint32_t flags, bool flip);
|
||||
|
||||
/** Signal that the given multimedia image handle is the new front image for
|
||||
* the stream.
|
||||
@@ -205,9 +247,22 @@ void wfc_server_stream_signal_mm_image_data(WFCNativeStreamType stream, uint32_t
|
||||
* @param width The image width, in pixels.
|
||||
* @param height The image height, in pixels.
|
||||
* @param pitch The image pitch, in bytes.
|
||||
* @param vpitch The image vertical pitch, in pixels.
|
||||
*/
|
||||
void wfc_server_stream_signal_raw_pixels(WFCNativeStreamType stream,
|
||||
uint32_t handle, uint32_t format, uint32_t width, uint32_t height, uint32_t pitch);
|
||||
uint32_t handle, uint32_t format, uint32_t width, uint32_t height,
|
||||
uint32_t pitch, uint32_t vpitch);
|
||||
|
||||
/** Signal that the given image is the new front image for the stream.
|
||||
*
|
||||
* The type of each image the stream must be the same e.g. it is not permitted
|
||||
* to mix opaque and raw pixel multimedia images within the same stream.
|
||||
*
|
||||
* @param stream The client stream identifier.
|
||||
* @param image Structure describing the image.
|
||||
*/
|
||||
void wfc_server_stream_signal_image(WFCNativeStreamType stream,
|
||||
const WFC_STREAM_IMAGE_T *image);
|
||||
|
||||
/** Register a stream as in use by a given process.
|
||||
*
|
||||
@@ -217,11 +272,21 @@ void wfc_server_stream_signal_raw_pixels(WFCNativeStreamType stream,
|
||||
*/
|
||||
void wfc_server_stream_register(WFCNativeStreamType stream, uint32_t pid_lo, uint32_t pid_hi);
|
||||
|
||||
/** Unregister a stream as in use.
|
||||
/** Unregister a stream as in use by a given process.
|
||||
*
|
||||
* @param stream The client stream identifier.
|
||||
* @param pid_lo The low 32-bits of the process ID.
|
||||
* @param pid_hi The high 32-bits of the process ID.
|
||||
*/
|
||||
void wfc_server_stream_unregister(WFCNativeStreamType stream);
|
||||
void wfc_server_stream_unregister(WFCNativeStreamType stream, uint32_t pid_lo, uint32_t pid_hi);
|
||||
|
||||
/** Retrieve the stream configuration information, if available.
|
||||
*
|
||||
* @param stream The client stream identifier.
|
||||
* @param info Address of block to receive the information on success.
|
||||
* @return VCOS_SUCCESS if successful, or an error code if not.
|
||||
*/
|
||||
uint32_t wfc_server_stream_get_info(WFCNativeStreamType stream, WFC_STREAM_INFO_T *info);
|
||||
|
||||
/** Set callback for when there is an image available. The stream must have
|
||||
* been created with either the WFC_STREAM_FLAGS_EGL or WFC_STREAM_FLAGS_BUF_AVAIL
|
||||
@@ -230,7 +295,6 @@ void wfc_server_stream_unregister(WFCNativeStreamType stream);
|
||||
* @param stream The client stream identifier.
|
||||
* @param image_available_cb Called when there is an image available.
|
||||
* @param image_available_data Passed to the callback.
|
||||
* @return VCOS_SUCCESS if successful, or an error code if not.
|
||||
*/
|
||||
void wfc_server_stream_on_image_available(WFCNativeStreamType stream,
|
||||
WFC_CALLBACK_T image_available_cb, void *image_available_data);
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
add_library (mmal_core
|
||||
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)
|
||||
|
||||
@@ -43,6 +43,16 @@ void mmal_buffer_header_acquire(MMAL_BUFFER_HEADER_T *header)
|
||||
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)
|
||||
{
|
||||
@@ -53,11 +63,18 @@ void mmal_buffer_header_release(MMAL_BUFFER_HEADER_T *header)
|
||||
if(--header->priv->refcount != 0)
|
||||
return;
|
||||
|
||||
header->length = 0;
|
||||
header->offset = 0;
|
||||
header->flags = 0;
|
||||
header->pts = 0;
|
||||
header->dts = 0;
|
||||
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;
|
||||
@@ -126,6 +143,12 @@ MMAL_DRIVER_BUFFER_T *mmal_buffer_header_driver_data(MMAL_BUFFER_HEADER_T *heade
|
||||
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
|
||||
@@ -156,3 +179,10 @@ void mmal_buffer_header_mem_unlock(MMAL_BUFFER_HEADER_T *header)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,11 @@ typedef struct MMAL_DRIVER_BUFFER_T MMAL_DRIVER_BUFFER_T;
|
||||
/** 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);
|
||||
@@ -72,4 +77,10 @@ MMAL_BUFFER_HEADER_T *mmal_buffer_header_initialise(void *mem, unsigned int leng
|
||||
*/
|
||||
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 */
|
||||
|
||||
802
interface/mmal/core/mmal_clock.c
Normal file
802
interface/mmal/core/mmal_clock.c
Normal file
@@ -0,0 +1,802 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING 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 offset; /**< time offset requested by the client (microseconds) */
|
||||
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 the client-supplied
|
||||
offset and 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 stop_thread;
|
||||
VCOS_SEMAPHORE_T event;
|
||||
VCOS_THREAD_T thread;
|
||||
|
||||
VCOS_MUTEX_T lock; /**< lock access to the request lists */
|
||||
|
||||
MMAL_TIMER_T timer; /**< used for scheduling client requests */
|
||||
|
||||
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 */
|
||||
int64_t media_time_offset;/**< media-time offset 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 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(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;
|
||||
|
||||
/* Only update the media-time if the clock is active */
|
||||
if (private->is_active)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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(&private->clock);
|
||||
|
||||
/* 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(&private->clock);
|
||||
|
||||
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 */
|
||||
static void mmal_clock_wake_thread(MMAL_CLOCK_PRIVATE_T *private)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Clock module public functions
|
||||
*****************************************************************************/
|
||||
/* Create new clock instance */
|
||||
MMAL_STATUS_T mmal_clock_create(MMAL_CLOCK_T **clock)
|
||||
{
|
||||
unsigned int i, size = sizeof(MMAL_CLOCK_PRIVATE_T);
|
||||
MMAL_BOOL_T timer_status = MMAL_FALSE;
|
||||
VCOS_STATUS_T lock_status = VCOS_EINVAL;
|
||||
VCOS_STATUS_T event_status = VCOS_EINVAL;
|
||||
MMAL_RATIONAL_T scale = { 1, 0 };
|
||||
VCOS_UNSIGNED priority;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
lock_status = vcos_mutex_create(&private->lock, "mmal-clock lock");
|
||||
if (lock_status != VCOS_SUCCESS)
|
||||
{
|
||||
LOG_ERROR("failed to create lock mutex %d", lock_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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
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));
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Default scale = 1.0, i.e. normal playback speed */
|
||||
mmal_clock_scale_set(&private->clock, scale);
|
||||
|
||||
*clock = &private->clock;
|
||||
return MMAL_SUCCESS;
|
||||
|
||||
error:
|
||||
if (lock_status == VCOS_SUCCESS) vcos_mutex_delete(&private->lock);
|
||||
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);
|
||||
vcos_free(private);
|
||||
return MMAL_ENOSPC;
|
||||
}
|
||||
|
||||
/* Destroy a clock instance */
|
||||
MMAL_STATUS_T mmal_clock_destroy(MMAL_CLOCK_T *clock)
|
||||
{
|
||||
MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T*)clock;
|
||||
|
||||
mmal_clock_stop_thread(private);
|
||||
|
||||
mmal_clock_request_flush(clock);
|
||||
|
||||
mmal_list_destroy(private->request.list_free);
|
||||
mmal_list_destroy(private->request.list_pending);
|
||||
|
||||
mmal_clock_timer_destroy(&private->timer);
|
||||
|
||||
vcos_mutex_delete(&private->lock);
|
||||
|
||||
vcos_semaphore_delete(&private->event);
|
||||
|
||||
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, int64_t offset,
|
||||
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 success;
|
||||
|
||||
LOG_TRACE("media time %"PRIi64" offset %"PRIi64, media_time, offset);
|
||||
|
||||
request = (MMAL_CLOCK_REQUEST_T*)mmal_list_pop_front(private->request.list_free);
|
||||
if (request == NULL)
|
||||
{
|
||||
LOG_ERROR("no more free clock request slots");
|
||||
return MMAL_ENOSPC;
|
||||
}
|
||||
|
||||
request->cb = cb;
|
||||
request->cb_data = cb_data;
|
||||
request->priv = priv;
|
||||
request->offset = offset;
|
||||
request->media_time = media_time;
|
||||
request->media_time_adj = media_time - (int64_t)(private->scale * (request->offset + CLOCK_TARGET_OFFSET) >> 16);
|
||||
|
||||
LOCK(private);
|
||||
success = mmal_clock_request_insert(private, request);
|
||||
UNLOCK(private);
|
||||
|
||||
/* Notify the worker thread */
|
||||
if (success)
|
||||
mmal_clock_wake_thread(private);
|
||||
|
||||
return success ? MMAL_SUCCESS : MMAL_EINVAL;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
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;
|
||||
|
||||
/* Reset the local media-time with the given time reference */
|
||||
mmal_clock_update_local_time(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);
|
||||
}
|
||||
}
|
||||
|
||||
if (wake_thread)
|
||||
mmal_clock_wake_thread(private);
|
||||
|
||||
return wake_thread ? MMAL_SUCCESS : MMAL_EINVAL;
|
||||
}
|
||||
|
||||
/* Set a media-time offset */
|
||||
MMAL_STATUS_T mmal_clock_media_time_offset_set(MMAL_CLOCK_T *clock, int64_t offset)
|
||||
{
|
||||
MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T*)clock;
|
||||
|
||||
LOG_TRACE("new offset %"PRIi64, offset);
|
||||
|
||||
private->media_time_offset = offset;
|
||||
|
||||
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);
|
||||
|
||||
mmal_clock_update_local_time(private);
|
||||
|
||||
LOCK(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)
|
||||
{
|
||||
MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T*)clock;
|
||||
|
||||
mmal_clock_update_local_time(private);
|
||||
|
||||
return private->media_time + (private->scale * private->media_time_offset >> 16);
|
||||
}
|
||||
|
||||
/* Return the media-time offset */
|
||||
int64_t mmal_clock_media_time_offset_get(MMAL_CLOCK_T *clock)
|
||||
{
|
||||
return ((MMAL_CLOCK_PRIVATE_T*)clock)->media_time_offset;
|
||||
}
|
||||
|
||||
/* 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_PARAMETER_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_PARAMETER_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_PARAMETER_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_PARAMETER_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;
|
||||
}
|
||||
205
interface/mmal/core/mmal_clock_private.h
Normal file
205
interface/mmal/core/mmal_clock_private.h
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef 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 offset Time offset (in microseconds) applied to the media-time. This can be used
|
||||
* to schedule the request slightly in advance of the media-time.
|
||||
* @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, int64_t offset,
|
||||
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);
|
||||
|
||||
/** Update the clock's media-time offset.
|
||||
*
|
||||
* @param clock The clock to update
|
||||
* @param media_time New media-time offset to be applied (microseconds)
|
||||
*
|
||||
* @return MMAL_SUCCESS on success
|
||||
*/
|
||||
MMAL_STATUS_T mmal_clock_media_time_offset_set(MMAL_CLOCK_T *clock, int64_t offset);
|
||||
|
||||
/** 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 media-time offset.
|
||||
*
|
||||
* @param clock The clock to query
|
||||
*
|
||||
* @return Current media-time offset in microseconds
|
||||
*/
|
||||
int64_t mmal_clock_media_time_offset_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_PARAMETER_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_PARAMETER_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_PARAMETER_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_PARAMETER_CLOCK_DISCONT_THRESHOLD_T *discont);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MMAL_CLOCK_PRIVATE_H */
|
||||
@@ -80,11 +80,14 @@ static MMAL_STATUS_T mmal_component_create_core(const char *name,
|
||||
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;
|
||||
@@ -94,6 +97,7 @@ static MMAL_STATUS_T mmal_component_create_core(const char *name,
|
||||
(*component)->name = component_name= (char *)&((MMAL_COMPONENT_CORE_PRIVATE_T *)(*component)->priv)[1];
|
||||
memcpy(component_name, name, name_length);
|
||||
(*component)->priv->refcount = 1;
|
||||
(*component)->priv->priority = VCOS_THREAD_PRI_NORMAL;
|
||||
|
||||
if(vcos_mutex_create(&private->lock, "mmal component lock") != VCOS_SUCCESS)
|
||||
{
|
||||
@@ -101,8 +105,6 @@ static MMAL_STATUS_T mmal_component_create_core(const char *name,
|
||||
return MMAL_ENOMEM;
|
||||
}
|
||||
|
||||
mmal_core_init();
|
||||
|
||||
vcos_mutex_lock(&mmal_core_lock);
|
||||
(*component)->id=mmal_core_instance_count++;
|
||||
vcos_mutex_unlock(&mmal_core_lock);
|
||||
@@ -147,30 +149,52 @@ static MMAL_STATUS_T mmal_component_create_core(const char *name,
|
||||
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;
|
||||
if ((*component)->control->buffer_size < (*component)->control->buffer_size_min)
|
||||
(*component)->control->buffer_size = (*component)->control->buffer_size_min;
|
||||
if ((*component)->control->buffer_num < (*component)->control->buffer_num_min)
|
||||
(*component)->control->buffer_num = (*component)->control->buffer_num_min;
|
||||
for (i = 0; i < (*component)->input_num; i++)
|
||||
{
|
||||
MMAL_PORT_T *port = (*component)->input[i];
|
||||
port->type = MMAL_PORT_TYPE_INPUT;
|
||||
port->index = 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;
|
||||
}
|
||||
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)
|
||||
@@ -229,6 +253,9 @@ static MMAL_STATUS_T mmal_component_destroy_internal(MMAL_COMPONENT_T *component
|
||||
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();
|
||||
@@ -261,6 +288,8 @@ static MMAL_STATUS_T mmal_component_release_internal(MMAL_COMPONENT_T *component
|
||||
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]);
|
||||
|
||||
/* Make sure the ports are all disabled */
|
||||
for(i = 0; i < component->input_num; i++)
|
||||
@@ -269,6 +298,9 @@ static MMAL_STATUS_T mmal_component_release_internal(MMAL_COMPONENT_T *component
|
||||
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);
|
||||
|
||||
@@ -313,6 +345,9 @@ void mmal_component_acquire(MMAL_COMPONENT_T *component)
|
||||
/** 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);
|
||||
|
||||
@@ -322,34 +357,78 @@ MMAL_STATUS_T mmal_component_release(MMAL_COMPONENT_T *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;
|
||||
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;
|
||||
}
|
||||
|
||||
status = component->priv->pf_enable(component);
|
||||
|
||||
/* 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;
|
||||
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;
|
||||
}
|
||||
|
||||
status = component->priv->pf_disable(component);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
@@ -373,7 +452,7 @@ MMAL_STATUS_T mmal_component_parameter_set(MMAL_PORT_T *control_port,
|
||||
(void)param;
|
||||
/* No generic component control parameters */
|
||||
LOG_ERROR("parameter id 0x%08x not supported", param->id);
|
||||
return MMAL_EINVAL;
|
||||
return MMAL_ENOSYS;
|
||||
}
|
||||
|
||||
MMAL_STATUS_T mmal_component_parameter_get(MMAL_PORT_T *control_port,
|
||||
@@ -383,7 +462,7 @@ MMAL_STATUS_T mmal_component_parameter_get(MMAL_PORT_T *control_port,
|
||||
(void)param;
|
||||
/* No generic component control parameters */
|
||||
LOG_ERROR("parameter id 0x%08x not supported", param->id);
|
||||
return MMAL_EINVAL;
|
||||
return MMAL_ENOSYS;
|
||||
}
|
||||
|
||||
static void mmal_component_init_control_port(MMAL_PORT_T *port)
|
||||
@@ -476,6 +555,7 @@ 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)
|
||||
@@ -492,7 +572,10 @@ MMAL_STATUS_T mmal_component_action_register(MMAL_COMPONENT_T *component,
|
||||
return MMAL_ENOMEM;
|
||||
}
|
||||
|
||||
status = vcos_thread_create(&private->action_thread, component->name, NULL,
|
||||
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)
|
||||
{
|
||||
@@ -570,6 +653,7 @@ static void mmal_core_init_once(void)
|
||||
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);
|
||||
@@ -579,7 +663,6 @@ static void mmal_core_init(void)
|
||||
return;
|
||||
}
|
||||
|
||||
vcos_init();
|
||||
mmal_logging_init();
|
||||
vcos_mutex_unlock(&mmal_core_lock);
|
||||
}
|
||||
@@ -595,6 +678,7 @@ static void mmal_core_deinit(void)
|
||||
|
||||
mmal_logging_deinit();
|
||||
vcos_mutex_unlock(&mmal_core_lock);
|
||||
vcos_deinit();
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
@@ -31,6 +31,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#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)
|
||||
@@ -62,6 +65,10 @@ struct MMAL_COMPONENT_PRIVATE_T
|
||||
/** 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.
|
||||
|
||||
@@ -132,7 +132,12 @@ uint32_t mmal_format_compare(MMAL_ES_FORMAT_T *fmt1, MMAL_ES_FORMAT_T *fmt2)
|
||||
result |= MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_ASPECT_RATIO;
|
||||
if (memcmp(&video1->frame_rate, &video2->frame_rate, sizeof(video1->frame_rate)))
|
||||
result |= MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_FRAME_RATE;
|
||||
if (memcmp(&video1->par, &video2->par, sizeof(*video1) - offsetof(MMAL_VIDEO_FORMAT_T, par)))
|
||||
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:
|
||||
@@ -166,6 +171,7 @@ MMAL_STATUS_T mmal_format_extradata_alloc(MMAL_ES_FORMAT_T *format, unsigned int
|
||||
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 */
|
||||
|
||||
@@ -286,3 +286,18 @@ void mmal_pool_callback_set(MMAL_POOL_T *pool, MMAL_POOL_BH_CB_T cb, void *userd
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "interface/mmal/mmal_parameters.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef _VIDEOCORE
|
||||
#include "vcfw/rtos/common/rtos_common_mem.h" /* mem_alloc */
|
||||
#endif
|
||||
|
||||
/** Only collect port stats if enabled in build. Performance could be
|
||||
* affected on an ARM since gettimeofday() involves a system call.
|
||||
*/
|
||||
@@ -45,7 +49,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#endif
|
||||
|
||||
static MMAL_STATUS_T mmal_port_private_parameter_get(MMAL_PORT_T *port,
|
||||
const MMAL_PARAMETER_HEADER_T *param);
|
||||
MMAL_PARAMETER_HEADER_T *param);
|
||||
|
||||
static MMAL_STATUS_T mmal_port_private_parameter_set(MMAL_PORT_T *port,
|
||||
const MMAL_PARAMETER_HEADER_T *param);
|
||||
@@ -82,12 +86,19 @@ typedef struct MMAL_PORT_PRIVATE_CORE_T
|
||||
/** Pool of buffers used between connected ports - output port only */
|
||||
MMAL_POOL_T* pool_for_connection;
|
||||
|
||||
/** Indicates whether the port is paused or not. Buffers received on
|
||||
* a paused port will be queued instead of being sent to the component. */
|
||||
MMAL_BOOL_T is_paused;
|
||||
/** Queue for buffers received from the client when in paused state */
|
||||
MMAL_BUFFER_HEADER_T* queue_first;
|
||||
/** Queue for buffers received from the client when in paused state */
|
||||
MMAL_BUFFER_HEADER_T** queue_last;
|
||||
|
||||
/** Per-port statistics collected directly by the MMAL core */
|
||||
MMAL_CORE_PORT_STATISTICS_T stats;
|
||||
|
||||
char *name; /**< Port name */
|
||||
unsigned int name_size; /** Size of the memory area reserved for the name string */
|
||||
|
||||
} MMAL_PORT_PRIVATE_CORE_T;
|
||||
|
||||
/*****************************************************************************
|
||||
@@ -97,6 +108,7 @@ static MMAL_STATUS_T mmal_port_enable_locked(MMAL_PORT_T *port, MMAL_PORT_BH_CB_
|
||||
static MMAL_STATUS_T mmal_port_enable_locked_connected(MMAL_PORT_T* output, MMAL_PORT_T* input);
|
||||
static MMAL_STATUS_T mmal_port_disable_locked(MMAL_PORT_T *port);
|
||||
static MMAL_STATUS_T mmal_port_populate_from_pool(MMAL_PORT_T* port, MMAL_POOL_T* pool);
|
||||
static MMAL_STATUS_T mmal_port_populate_clock_ports(MMAL_PORT_T* output, MMAL_PORT_T* input, MMAL_POOL_T* pool);
|
||||
static MMAL_STATUS_T mmal_port_connect_default(MMAL_PORT_T *port, MMAL_PORT_T *other_port);
|
||||
static void mmal_port_set_input_or_output(MMAL_PORT_T* port, MMAL_PORT_T** input_port, MMAL_PORT_T** output_port);
|
||||
static void mmal_port_connected_input_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
|
||||
@@ -166,6 +178,7 @@ MMAL_PORT_T *mmal_port_alloc(MMAL_COMPONENT_T *component, MMAL_PORT_TYPE_T type,
|
||||
port->name = core->name = ((char *)(port->priv->core+1)) + extra_size;
|
||||
core->name_size = name_size;
|
||||
mmal_port_name_update(port);
|
||||
core->queue_last = &core->queue_first;
|
||||
|
||||
port->priv->pf_connect = mmal_port_connect_default;
|
||||
|
||||
@@ -283,9 +296,9 @@ MMAL_STATUS_T mmal_port_format_commit(MMAL_PORT_T *port)
|
||||
}
|
||||
|
||||
if (port->format->encoding == 0)
|
||||
strcpy(encoding_string, "<NO-FORMAT>");
|
||||
snprintf(encoding_string, sizeof(encoding_string), "<NO-FORMAT>");
|
||||
else
|
||||
sprintf(encoding_string, "%4.4s", (char*)&port->format->encoding);
|
||||
snprintf(encoding_string, sizeof(encoding_string), "%4.4s", (char*)&port->format->encoding);
|
||||
|
||||
LOG_TRACE("%s(%i:%i) port %p format %i:%s",
|
||||
port->component->name, (int)port->type, (int)port->index, port,
|
||||
@@ -406,7 +419,7 @@ static MMAL_STATUS_T mmal_port_enable_locked(MMAL_PORT_T *port, MMAL_PORT_BH_CB_
|
||||
//FIXME: move before is_enabled is set ?
|
||||
if (connected_port)
|
||||
{
|
||||
if (port->type == MMAL_PORT_TYPE_INPUT)
|
||||
if (port->type == MMAL_PORT_TYPE_INPUT || (port->type == MMAL_PORT_TYPE_CLOCK && !core->allocate_pool))
|
||||
core->buffer_header_callback = mmal_port_connected_input_cb;
|
||||
else
|
||||
status = mmal_port_enable_locked_connected(port, connected_port);
|
||||
@@ -461,13 +474,18 @@ static MMAL_STATUS_T mmal_port_enable_locked_connected(MMAL_PORT_T* output, MMAL
|
||||
|
||||
UNLOCK_PORT(input);
|
||||
if (pool_port == output)
|
||||
{
|
||||
UNLOCK_PORT(output);
|
||||
}
|
||||
|
||||
/* Port pool creation must be done without the lock held */
|
||||
pool = mmal_port_pool_create(pool_port, pool_port->buffer_num, buffer_size);
|
||||
|
||||
if (pool_port == output)
|
||||
{
|
||||
/* coverity[missing_unlock] Output port was already locked by caller; we should leave it locked */
|
||||
LOCK_PORT(output);
|
||||
}
|
||||
LOCK_PORT(input);
|
||||
|
||||
if (!pool)
|
||||
@@ -479,8 +497,17 @@ static MMAL_STATUS_T mmal_port_enable_locked_connected(MMAL_PORT_T* output, MMAL
|
||||
pool_core->pool_for_connection = pool;
|
||||
mmal_pool_callback_set(pool_core->pool_for_connection, mmal_port_connected_pool_cb, output);
|
||||
|
||||
/* Put the buffers into the output port */
|
||||
status = mmal_port_populate_from_pool(output, pool_port->priv->core->pool_for_connection);
|
||||
if ((output->type == MMAL_PORT_TYPE_CLOCK) && (input->type == MMAL_PORT_TYPE_CLOCK))
|
||||
{
|
||||
/* Clock ports need buffers to send clock updates, so
|
||||
* populate both clock ports */
|
||||
status = mmal_port_populate_clock_ports(output, input, pool_port->priv->core->pool_for_connection);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Put the buffers into the output port */
|
||||
status = mmal_port_populate_from_pool(output, pool_port->priv->core->pool_for_connection);
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
@@ -531,6 +558,7 @@ MMAL_STATUS_T mmal_port_disable(MMAL_PORT_T *port)
|
||||
static MMAL_STATUS_T mmal_port_disable_locked(MMAL_PORT_T *port)
|
||||
{
|
||||
MMAL_PORT_PRIVATE_CORE_T* core = port->priv->core;
|
||||
MMAL_BUFFER_HEADER_T *buffer;
|
||||
MMAL_STATUS_T status;
|
||||
|
||||
if (!port->is_enabled)
|
||||
@@ -561,6 +589,17 @@ static MMAL_STATUS_T mmal_port_disable_locked(MMAL_PORT_T *port)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Flush our internal queue */
|
||||
buffer = port->priv->core->queue_first;
|
||||
while (buffer)
|
||||
{
|
||||
MMAL_BUFFER_HEADER_T *next = buffer->next;
|
||||
mmal_port_buffer_header_callback(port, buffer);
|
||||
buffer = next;
|
||||
}
|
||||
port->priv->core->queue_first = 0;
|
||||
port->priv->core->queue_last = &port->priv->core->queue_first;
|
||||
|
||||
/* Wait for all the buffers to have come back from the component */
|
||||
LOG_DEBUG("%s waiting for %i buffers left in transit", port->name, (int)IN_TRANSIT_COUNT(port));
|
||||
IN_TRANSIT_WAIT(port);
|
||||
@@ -568,7 +607,8 @@ static MMAL_STATUS_T mmal_port_disable_locked(MMAL_PORT_T *port)
|
||||
|
||||
port->priv->core->buffer_header_callback = NULL;
|
||||
|
||||
if (core->connected_port && port->type == MMAL_PORT_TYPE_OUTPUT)
|
||||
if ((core->connected_port && port->type == MMAL_PORT_TYPE_OUTPUT) ||
|
||||
(port->type == MMAL_PORT_TYPE_CLOCK && core->allocate_pool))
|
||||
mmal_port_disable(core->connected_port);
|
||||
|
||||
return status;
|
||||
@@ -578,7 +618,7 @@ static MMAL_STATUS_T mmal_port_disable_locked(MMAL_PORT_T *port)
|
||||
MMAL_STATUS_T mmal_port_send_buffer(MMAL_PORT_T *port,
|
||||
MMAL_BUFFER_HEADER_T *buffer)
|
||||
{
|
||||
MMAL_STATUS_T status;
|
||||
MMAL_STATUS_T status = MMAL_SUCCESS;
|
||||
|
||||
if (!port || !port->priv)
|
||||
{
|
||||
@@ -617,7 +657,18 @@ MMAL_STATUS_T mmal_port_send_buffer(MMAL_PORT_T *port,
|
||||
}
|
||||
|
||||
IN_TRANSIT_INCREMENT(port);
|
||||
status = port->priv->pf_send(port, buffer);
|
||||
|
||||
if (port->priv->core->is_paused)
|
||||
{
|
||||
/* Add buffer to our internal queue */
|
||||
*port->priv->core->queue_last = buffer;
|
||||
port->priv->core->queue_last = &buffer->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Send buffer to component */
|
||||
status = port->priv->pf_send(port, buffer);
|
||||
}
|
||||
|
||||
if (status != MMAL_SUCCESS)
|
||||
{
|
||||
@@ -636,6 +687,7 @@ MMAL_STATUS_T mmal_port_send_buffer(MMAL_PORT_T *port,
|
||||
/** Flush a port */
|
||||
MMAL_STATUS_T mmal_port_flush(MMAL_PORT_T *port)
|
||||
{
|
||||
MMAL_BUFFER_HEADER_T *buffer = 0;
|
||||
MMAL_STATUS_T status;
|
||||
|
||||
if (!port || !port->priv)
|
||||
@@ -647,9 +699,25 @@ MMAL_STATUS_T mmal_port_flush(MMAL_PORT_T *port)
|
||||
if (!port->priv->pf_flush)
|
||||
return MMAL_ENOSYS;
|
||||
|
||||
mmal_component_action_lock(port->component);
|
||||
LOCK_SENDING(port);
|
||||
status = port->priv->pf_flush(port);
|
||||
if (status == MMAL_SUCCESS)
|
||||
{
|
||||
/* Flush our internal queue */
|
||||
buffer = port->priv->core->queue_first;
|
||||
port->priv->core->queue_first = 0;
|
||||
port->priv->core->queue_last = &port->priv->core->queue_first;
|
||||
}
|
||||
UNLOCK_SENDING(port);
|
||||
mmal_component_action_unlock(port->component);
|
||||
|
||||
while (buffer)
|
||||
{
|
||||
MMAL_BUFFER_HEADER_T *next = buffer->next;
|
||||
mmal_port_buffer_header_callback(port, buffer);
|
||||
buffer = next;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -730,8 +798,6 @@ void mmal_port_buffer_header_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *b
|
||||
buffer ? (int)buffer->offset : 0, buffer ? (int)buffer->length : 0);
|
||||
#endif
|
||||
|
||||
IN_TRANSIT_DECREMENT(port);
|
||||
|
||||
if (!vcos_verify(IN_TRANSIT_COUNT(port) >= 0))
|
||||
LOG_ERROR("%s: buffer headers in transit < 0 (%d)", port->name, (int)IN_TRANSIT_COUNT(port));
|
||||
|
||||
@@ -741,6 +807,8 @@ void mmal_port_buffer_header_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *b
|
||||
}
|
||||
|
||||
port->priv->core->buffer_header_callback(port, buffer);
|
||||
|
||||
IN_TRANSIT_DECREMENT(port);
|
||||
}
|
||||
|
||||
/** Event callback */
|
||||
@@ -773,6 +841,12 @@ MMAL_STATUS_T mmal_port_connect(MMAL_PORT_T *port, MMAL_PORT_T *other_port)
|
||||
return MMAL_EINVAL;
|
||||
}
|
||||
|
||||
if ((port->type == MMAL_PORT_TYPE_CLOCK) && (port->type != other_port->type))
|
||||
{
|
||||
LOG_ERROR("invalid port connection");
|
||||
return MMAL_EINVAL;
|
||||
}
|
||||
|
||||
LOG_TRACE("connecting %s(%p) to %s(%p)", port->name, port, other_port->name, other_port);
|
||||
|
||||
if (!port->priv->pf_connect || !other_port->priv->pf_connect)
|
||||
@@ -781,8 +855,16 @@ MMAL_STATUS_T mmal_port_connect(MMAL_PORT_T *port, MMAL_PORT_T *other_port)
|
||||
return MMAL_ENOSYS;
|
||||
}
|
||||
|
||||
mmal_port_set_input_or_output(port, &input_port, &output_port);
|
||||
mmal_port_set_input_or_output(other_port, &input_port, &output_port);
|
||||
if (port->type == MMAL_PORT_TYPE_CLOCK)
|
||||
{
|
||||
output_port = port;
|
||||
input_port = other_port;
|
||||
}
|
||||
else
|
||||
{
|
||||
mmal_port_set_input_or_output(port, &input_port, &output_port);
|
||||
mmal_port_set_input_or_output(other_port, &input_port, &output_port);
|
||||
}
|
||||
|
||||
if (!input_port || !output_port)
|
||||
{
|
||||
@@ -799,8 +881,10 @@ MMAL_STATUS_T mmal_port_connect(MMAL_PORT_T *port, MMAL_PORT_T *other_port)
|
||||
|
||||
if (core->connected_port || other_core->connected_port)
|
||||
{
|
||||
#ifdef VCOS_LOGGING_ENABLED
|
||||
MMAL_PORT_T* problem_port = core->connected_port ? port : other_port;
|
||||
MMAL_PORT_T* connected_port = problem_port->priv->core->connected_port;
|
||||
#endif
|
||||
|
||||
LOG_ERROR("port %p is already connected to port %p", problem_port, connected_port);
|
||||
status = MMAL_EISCONN;
|
||||
@@ -842,6 +926,7 @@ MMAL_STATUS_T mmal_port_disconnect(MMAL_PORT_T *port)
|
||||
{
|
||||
MMAL_PORT_PRIVATE_CORE_T* core;
|
||||
MMAL_PORT_T* other_port;
|
||||
MMAL_POOL_T* pool = NULL;
|
||||
MMAL_STATUS_T status = MMAL_SUCCESS;
|
||||
|
||||
if (!port || !port->priv)
|
||||
@@ -874,7 +959,7 @@ MMAL_STATUS_T mmal_port_disconnect(MMAL_PORT_T *port)
|
||||
}
|
||||
|
||||
if (port->priv->core->pool_for_connection)
|
||||
mmal_pool_destroy(port->priv->core->pool_for_connection);
|
||||
pool = port->priv->core->pool_for_connection;
|
||||
port->priv->core->pool_for_connection = NULL;
|
||||
}
|
||||
|
||||
@@ -893,6 +978,10 @@ MMAL_STATUS_T mmal_port_disconnect(MMAL_PORT_T *port)
|
||||
|
||||
finish:
|
||||
UNLOCK_PORT(port);
|
||||
|
||||
if (pool)
|
||||
mmal_pool_destroy(pool);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -915,7 +1004,11 @@ uint8_t *mmal_port_payload_alloc(MMAL_PORT_T *port, uint32_t payload_size)
|
||||
if (!port->priv->pf_payload_alloc)
|
||||
{
|
||||
/* Revert to using the heap */
|
||||
#ifdef _VIDEOCORE
|
||||
mem = (void *)mem_alloc(payload_size, 32, MEM_FLAG_DIRECT, port->name);
|
||||
#else
|
||||
mem = vcos_malloc(payload_size, "mmal payload");
|
||||
#endif
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -943,7 +1036,11 @@ void mmal_port_payload_free(MMAL_PORT_T *port, uint8_t *payload)
|
||||
if (!port->priv->pf_payload_alloc)
|
||||
{
|
||||
/* Revert to using the heap */
|
||||
#ifdef _VIDEOCORE
|
||||
mem_release((MEM_HANDLE_T)payload);
|
||||
#else
|
||||
vcos_free(payload);
|
||||
#endif
|
||||
mmal_port_release(port);
|
||||
return;
|
||||
}
|
||||
@@ -1002,6 +1099,45 @@ error:
|
||||
return MMAL_ENOSPC;
|
||||
}
|
||||
|
||||
/** Populate clock ports from the given pool */
|
||||
static MMAL_STATUS_T mmal_port_populate_clock_ports(MMAL_PORT_T* output, MMAL_PORT_T* input, MMAL_POOL_T* pool)
|
||||
{
|
||||
MMAL_STATUS_T status = MMAL_SUCCESS;
|
||||
MMAL_BUFFER_HEADER_T *buffer;
|
||||
|
||||
if (!output->priv->pf_send || !input->priv->pf_send)
|
||||
return MMAL_ENOSYS;
|
||||
|
||||
LOG_TRACE("output %s %p, input %s %p, pool: %p", output->name, output, input->name, input, pool);
|
||||
|
||||
buffer = mmal_queue_get(pool->queue);
|
||||
while (buffer)
|
||||
{
|
||||
status = mmal_port_send_buffer(output, buffer);
|
||||
if (status != MMAL_SUCCESS)
|
||||
{
|
||||
LOG_ERROR("failed to send buffer to clock port %s", output->name);
|
||||
mmal_buffer_header_release(buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
buffer = mmal_queue_get(pool->queue);
|
||||
if (buffer)
|
||||
{
|
||||
status = mmal_port_send_buffer(input, buffer);
|
||||
if (status != MMAL_SUCCESS)
|
||||
{
|
||||
LOG_ERROR("failed to send buffer to clock port %s", output->name);
|
||||
mmal_buffer_header_release(buffer);
|
||||
break;
|
||||
}
|
||||
buffer = mmal_queue_get(pool->queue);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/** Populate an output port with a pool of buffers */
|
||||
static MMAL_STATUS_T mmal_port_populate_from_pool(MMAL_PORT_T* port, MMAL_POOL_T* pool)
|
||||
{
|
||||
@@ -1160,16 +1296,13 @@ static void mmal_port_name_update(MMAL_PORT_T *port)
|
||||
{
|
||||
MMAL_PORT_PRIVATE_CORE_T* core = port->priv->core;
|
||||
|
||||
snprintf(core->name, core->name_size - 1, PORT_NAME_FORMAT,
|
||||
port->component->name,
|
||||
port->type == MMAL_PORT_TYPE_CONTROL ? "ctr" :
|
||||
port->type == MMAL_PORT_TYPE_INPUT ? "in" :
|
||||
port->type == MMAL_PORT_TYPE_OUTPUT ? "out" : "invalid", (int)port->index,
|
||||
vcos_snprintf(core->name, core->name_size - 1, PORT_NAME_FORMAT,
|
||||
port->component->name, mmal_port_type_to_string(port->type), (int)port->index,
|
||||
port->format && port->format->encoding ? '(' : '\0',
|
||||
port->format && port->format->encoding ? (char *)&port->format->encoding : "");
|
||||
}
|
||||
|
||||
static MMAL_STATUS_T mmal_port_get_core_stats(MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param)
|
||||
static MMAL_STATUS_T mmal_port_get_core_stats(MMAL_PORT_T *port, MMAL_PARAMETER_HEADER_T *param)
|
||||
{
|
||||
MMAL_PARAMETER_CORE_STATISTICS_T *stats_param = (MMAL_PARAMETER_CORE_STATISTICS_T*)param;
|
||||
MMAL_CORE_STATISTICS_T *stats = &stats_param->stats;
|
||||
@@ -1187,7 +1320,7 @@ static MMAL_STATUS_T mmal_port_get_core_stats(MMAL_PORT_T *port, const MMAL_PARA
|
||||
}
|
||||
*stats = *src_stats;
|
||||
if (stats_param->reset)
|
||||
memset(src_stats, 0, sizeof(port->priv->core->stats));
|
||||
memset(src_stats, 0, sizeof(*src_stats));
|
||||
vcos_mutex_unlock(&core->stats_lock);
|
||||
return MMAL_SUCCESS;
|
||||
}
|
||||
@@ -1220,7 +1353,7 @@ static void mmal_port_update_port_stats(MMAL_PORT_T *port, MMAL_CORE_STATS_DIR d
|
||||
}
|
||||
|
||||
static MMAL_STATUS_T mmal_port_private_parameter_get(MMAL_PORT_T *port,
|
||||
const MMAL_PARAMETER_HEADER_T *param)
|
||||
MMAL_PARAMETER_HEADER_T *param)
|
||||
{
|
||||
switch (param->id)
|
||||
{
|
||||
@@ -1242,4 +1375,44 @@ static MMAL_STATUS_T mmal_port_private_parameter_set(MMAL_PORT_T *port,
|
||||
}
|
||||
}
|
||||
|
||||
MMAL_STATUS_T mmal_port_pause(MMAL_PORT_T *port, MMAL_BOOL_T pause)
|
||||
{
|
||||
MMAL_STATUS_T status = MMAL_SUCCESS;
|
||||
|
||||
LOCK_SENDING(port);
|
||||
|
||||
/* When resuming from pause, we send all our queued buffers to the port */
|
||||
if (!pause && port->is_enabled)
|
||||
{
|
||||
MMAL_BUFFER_HEADER_T *buffer = port->priv->core->queue_first;
|
||||
while (buffer)
|
||||
{
|
||||
MMAL_BUFFER_HEADER_T *next = buffer->next;
|
||||
status = port->priv->pf_send(port, buffer);
|
||||
if (status != MMAL_SUCCESS)
|
||||
{
|
||||
buffer->next = next;
|
||||
break;
|
||||
}
|
||||
buffer = next;
|
||||
}
|
||||
|
||||
/* If for some reason we could not send one of the buffers, we just
|
||||
* leave all the buffers in our internal queue and return an error. */
|
||||
if (status != MMAL_SUCCESS)
|
||||
{
|
||||
port->priv->core->queue_first = buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
port->priv->core->queue_first = 0;
|
||||
port->priv->core->queue_last = &port->priv->core->queue_first;
|
||||
}
|
||||
}
|
||||
|
||||
if (status == MMAL_SUCCESS)
|
||||
port->priv->core->is_paused = pause;
|
||||
|
||||
UNLOCK_SENDING(port);
|
||||
return status;
|
||||
}
|
||||
|
||||
584
interface/mmal/core/mmal_port_clock.c
Normal file
584
interface/mmal/core/mmal_port_clock.c
Normal file
@@ -0,0 +1,584 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING 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 8
|
||||
|
||||
/** Private clock port context */
|
||||
typedef struct MMAL_PORT_MODULE_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_PORT_MODULE_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_STATUS_T status = MMAL_SUCCESS;
|
||||
MMAL_CLOCK_PAYLOAD_T payload;
|
||||
|
||||
if (buffer->length != sizeof(MMAL_CLOCK_PAYLOAD_T))
|
||||
{
|
||||
LOG_ERROR("invalid buffer length %d", buffer->length);
|
||||
return MMAL_EINVAL;
|
||||
}
|
||||
|
||||
mmal_buffer_header_mem_lock(buffer);
|
||||
memcpy(&payload, buffer->data, sizeof(MMAL_CLOCK_PAYLOAD_T));
|
||||
mmal_buffer_header_mem_unlock(buffer);
|
||||
|
||||
if (payload.magic != MMAL_CLOCK_PAYLOAD_MAGIC)
|
||||
{
|
||||
LOG_ERROR("buffer corrupt (magic %4.4s)", (char*)&payload.magic);
|
||||
return MMAL_EINVAL;
|
||||
}
|
||||
|
||||
LOG_TRACE("port %s length %d id %4.4s time %"PRIi64,
|
||||
port->name, buffer->length, (char*)&payload.id, payload.time);
|
||||
|
||||
switch (payload.id)
|
||||
{
|
||||
case MMAL_CLOCK_PAYLOAD_TIME:
|
||||
mmal_clock_media_time_set(port->priv->module->clock, payload.time);
|
||||
break;
|
||||
case MMAL_CLOCK_PAYLOAD_SCALE:
|
||||
mmal_clock_scale_set(port->priv->module->clock, payload.data.scale);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("invalid id %4.4s", (char*)&payload.id);
|
||||
status = MMAL_EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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_MODULE_T *module = port->priv->module;
|
||||
|
||||
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(module->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->module->queue);
|
||||
while (buffer)
|
||||
{
|
||||
mmal_port_buffer_header_callback(port, buffer);
|
||||
buffer = mmal_queue_get(port->priv->module->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_PORT_MODULE_T *module = port->priv->module;
|
||||
MMAL_CLOCK_PAYLOAD_T event;
|
||||
|
||||
switch (param->id)
|
||||
{
|
||||
case MMAL_PARAMETER_CLOCK_REFERENCE:
|
||||
{
|
||||
const MMAL_PARAMETER_BOOLEAN_T *p = (const MMAL_PARAMETER_BOOLEAN_T*)param;
|
||||
module->is_reference = p->enable;
|
||||
event.id = MMAL_CLOCK_PAYLOAD_REFERENCE;
|
||||
event.time = mmal_clock_media_time_get(module->clock);
|
||||
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_clock_active_set(module->clock, p->enable);
|
||||
event.id = MMAL_CLOCK_PAYLOAD_ACTIVE;
|
||||
event.time = mmal_clock_media_time_get(module->clock);
|
||||
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_PAYLOAD_SCALE;
|
||||
event.time = mmal_clock_media_time_get(module->clock);
|
||||
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_PAYLOAD_INVALID;
|
||||
}
|
||||
break;
|
||||
case MMAL_PARAMETER_CLOCK_TIME_OFFSET:
|
||||
{
|
||||
const MMAL_PARAMETER_INT64_T *p = (const MMAL_PARAMETER_INT64_T*)param;
|
||||
status = mmal_port_clock_media_time_offset_set(port, p->value);
|
||||
event.id = MMAL_CLOCK_PAYLOAD_INVALID;
|
||||
}
|
||||
break;
|
||||
case MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD:
|
||||
{
|
||||
const MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD_T *p = (MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD_T *)param;
|
||||
status = mmal_clock_update_threshold_set(module->clock, p);
|
||||
event.id = MMAL_CLOCK_PAYLOAD_INVALID;
|
||||
}
|
||||
break;
|
||||
case MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD:
|
||||
{
|
||||
const MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD_T *p = (MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD_T *)param;
|
||||
status = mmal_clock_discont_threshold_set(module->clock, p);
|
||||
event.id = MMAL_CLOCK_PAYLOAD_INVALID;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return MMAL_ENOSYS;
|
||||
}
|
||||
|
||||
/* Notify the component */
|
||||
if (module->event_cb && status == MMAL_SUCCESS && event.id != MMAL_CLOCK_PAYLOAD_INVALID)
|
||||
module->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_MODULE_T *module = port->priv->module;
|
||||
|
||||
switch (param->id)
|
||||
{
|
||||
case MMAL_PARAMETER_CLOCK_REFERENCE:
|
||||
{
|
||||
MMAL_PARAMETER_BOOLEAN_T *p = (MMAL_PARAMETER_BOOLEAN_T*)param;
|
||||
p->enable = module->is_reference;
|
||||
}
|
||||
break;
|
||||
case MMAL_PARAMETER_CLOCK_ACTIVE:
|
||||
{
|
||||
MMAL_PARAMETER_BOOLEAN_T *p = (MMAL_PARAMETER_BOOLEAN_T*)param;
|
||||
p->enable = mmal_clock_is_active(module->clock);
|
||||
}
|
||||
break;
|
||||
case MMAL_PARAMETER_CLOCK_SCALE:
|
||||
{
|
||||
MMAL_PARAMETER_RATIONAL_T *p = (MMAL_PARAMETER_RATIONAL_T*)param;
|
||||
p->value = mmal_clock_scale_get(module->clock);
|
||||
}
|
||||
break;
|
||||
case MMAL_PARAMETER_CLOCK_TIME:
|
||||
{
|
||||
MMAL_PARAMETER_INT64_T *p = (MMAL_PARAMETER_INT64_T*)param;
|
||||
p->value = mmal_clock_media_time_get(module->clock);
|
||||
}
|
||||
break;
|
||||
case MMAL_PARAMETER_CLOCK_TIME_OFFSET:
|
||||
{
|
||||
MMAL_PARAMETER_INT64_T *p = (MMAL_PARAMETER_INT64_T*)param;
|
||||
p->value = mmal_clock_media_time_offset_get(module->clock);
|
||||
}
|
||||
break;
|
||||
case MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD:
|
||||
{
|
||||
MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD_T *p = (MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD_T *)param;
|
||||
mmal_clock_update_threshold_get(module->clock, p);
|
||||
}
|
||||
break;
|
||||
case MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD:
|
||||
{
|
||||
MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD_T *p = (MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD_T *)param;
|
||||
mmal_clock_discont_threshold_get(module->clock, p);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return MMAL_ENOSYS;
|
||||
}
|
||||
return MMAL_SUCCESS;
|
||||
}
|
||||
|
||||
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_MODULE_T *module = port->priv->module;
|
||||
|
||||
if (mmal_clock_is_active(module->clock))
|
||||
mmal_clock_active_set(module->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 a payload buffer to a connected port/client */
|
||||
static MMAL_STATUS_T mmal_port_clock_forward_payload(MMAL_PORT_T *port, const MMAL_CLOCK_PAYLOAD_T *payload)
|
||||
{
|
||||
MMAL_STATUS_T status;
|
||||
MMAL_BUFFER_HEADER_T *buffer;
|
||||
|
||||
buffer = mmal_queue_get(port->priv->module->queue);
|
||||
if (!buffer)
|
||||
{
|
||||
LOG_ERROR("no free buffers available");
|
||||
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->module->queue, buffer);
|
||||
goto end;
|
||||
}
|
||||
buffer->length = sizeof(MMAL_CLOCK_PAYLOAD_T);
|
||||
memcpy(buffer->data, payload, buffer->length);
|
||||
mmal_buffer_header_mem_unlock(buffer);
|
||||
|
||||
mmal_port_buffer_header_callback(port, buffer);
|
||||
|
||||
end:
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Send a clock time update to a connected port/client */
|
||||
static MMAL_STATUS_T mmal_port_clock_forward_media_time(MMAL_PORT_T *port, int64_t media_time)
|
||||
{
|
||||
MMAL_CLOCK_PAYLOAD_T payload;
|
||||
|
||||
payload.id = MMAL_CLOCK_PAYLOAD_TIME;
|
||||
payload.magic = MMAL_CLOCK_PAYLOAD_MAGIC;
|
||||
payload.time = media_time;
|
||||
|
||||
return mmal_port_clock_forward_payload(port, &payload);
|
||||
}
|
||||
|
||||
/* Send a clock scale update to a connected port/client */
|
||||
static MMAL_STATUS_T mmal_port_clock_forward_scale(MMAL_PORT_T *port, MMAL_RATIONAL_T scale)
|
||||
{
|
||||
MMAL_CLOCK_PAYLOAD_T payload;
|
||||
|
||||
payload.id = MMAL_CLOCK_PAYLOAD_SCALE;
|
||||
payload.magic = MMAL_CLOCK_PAYLOAD_MAGIC;
|
||||
payload.time = mmal_clock_media_time_get(port->priv->module->clock);
|
||||
payload.data.scale = scale;
|
||||
|
||||
return mmal_port_clock_forward_payload(port, &payload);
|
||||
}
|
||||
|
||||
/* Initialise all callbacks and setup internal resources */
|
||||
static MMAL_STATUS_T mmal_port_clock_setup(MMAL_PORT_T *port, MMAL_PORT_CLOCK_EVENT_CB event_cb)
|
||||
{
|
||||
MMAL_STATUS_T status;
|
||||
|
||||
status = mmal_clock_create(&port->priv->module->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->module->clock->user_data = port;
|
||||
|
||||
port->buffer_size = sizeof(MMAL_CLOCK_PAYLOAD_T);
|
||||
port->buffer_size_min = sizeof(MMAL_CLOCK_PAYLOAD_T);
|
||||
port->buffer_num_min = MMAL_PORT_CLOCK_BUFFERS_MIN;
|
||||
port->buffer_num_recommended = MMAL_PORT_CLOCK_BUFFERS_MIN;
|
||||
|
||||
port->priv->module->event_cb = event_cb;
|
||||
port->priv->module->queue = mmal_queue_create();
|
||||
if (!port->priv->module->queue)
|
||||
{
|
||||
mmal_clock_destroy(port->priv->module->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->module->queue);
|
||||
mmal_clock_destroy(port->priv->module->clock);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Public functions
|
||||
*****************************************************************************/
|
||||
/* Allocate a clock port */
|
||||
MMAL_PORT_T* mmal_port_clock_alloc(MMAL_COMPONENT_T *component, MMAL_PORT_CLOCK_EVENT_CB event_cb)
|
||||
{
|
||||
MMAL_PORT_T *port;
|
||||
|
||||
port = mmal_port_alloc(component, MMAL_PORT_TYPE_CLOCK, sizeof(MMAL_PORT_MODULE_T));
|
||||
if (!port)
|
||||
return NULL;
|
||||
|
||||
if (mmal_port_clock_setup(port, 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, 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, sizeof(MMAL_PORT_MODULE_T));
|
||||
if (!ports)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < ports_num; i++)
|
||||
{
|
||||
if (mmal_port_clock_setup(ports[i], 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, int64_t offset,
|
||||
MMAL_PORT_CLOCK_REQUEST_CB cb, void *cb_data)
|
||||
{
|
||||
return mmal_clock_request_add(port->priv->module->clock, media_time, offset,
|
||||
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->module->clock);
|
||||
}
|
||||
|
||||
/* Set the media-time on the clock port */
|
||||
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->module->clock, media_time);
|
||||
if (status != MMAL_SUCCESS)
|
||||
{
|
||||
LOG_DEBUG("clock update ignored");
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Only forward time updates if this port is set as a reference clock port */
|
||||
if (port->priv->module->is_reference)
|
||||
mmal_port_clock_forward_media_time(port, mmal_clock_media_time_get(port->priv->module->clock));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Set the media-time offset on the clock port */
|
||||
MMAL_STATUS_T mmal_port_clock_media_time_offset_set(MMAL_PORT_T *port, int64_t offset)
|
||||
{
|
||||
MMAL_STATUS_T status;
|
||||
|
||||
status = mmal_clock_media_time_offset_set(port->priv->module->clock, offset);
|
||||
|
||||
/* The media-time has effectively changed, so need to inform connected clock ports */
|
||||
if (port->priv->module->is_reference)
|
||||
mmal_port_clock_forward_media_time(port, mmal_clock_media_time_get(port->priv->module->clock));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Return the current media-time */
|
||||
int64_t mmal_port_clock_media_time_get(MMAL_PORT_T *port)
|
||||
{
|
||||
return mmal_clock_media_time_get(port->priv->module->clock);
|
||||
}
|
||||
|
||||
/* Return the media-time offset */
|
||||
int64_t mmal_port_clock_media_time_offset_get(MMAL_PORT_T *port)
|
||||
{
|
||||
return mmal_clock_media_time_offset_get(port->priv->module->clock);
|
||||
}
|
||||
|
||||
/* Set the clock scale factor */
|
||||
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->module->clock, scale);
|
||||
|
||||
if (port->priv->module->is_reference)
|
||||
mmal_port_clock_forward_scale(port, scale);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Return the clock scale factor */
|
||||
MMAL_RATIONAL_T mmal_port_clock_scale_get(MMAL_PORT_T *port)
|
||||
{
|
||||
return mmal_clock_scale_get(port->priv->module->clock);
|
||||
}
|
||||
|
||||
/* Return TRUE if clock is running (media-time is advancing) */
|
||||
MMAL_BOOL_T mmal_port_clock_is_active(MMAL_PORT_T *port)
|
||||
{
|
||||
return mmal_clock_is_active(port->priv->module->clock);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,9 @@ 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"
|
||||
|
||||
/** Definition of a port. */
|
||||
typedef struct MMAL_PORT_PRIVATE_T
|
||||
{
|
||||
@@ -75,4 +78,142 @@ 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);
|
||||
|
||||
/*****************************************************************************
|
||||
* 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_PAYLOAD_T *event);
|
||||
|
||||
/** Allocate a clock port.
|
||||
*
|
||||
* @param component The component requesting the alloc
|
||||
* @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, 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 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, 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 offset Time offset (in microseconds) applied to the media-time. This can be used
|
||||
* to schedule the request slightly in advance of the media-time.
|
||||
* @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, int64_t offset,
|
||||
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);
|
||||
|
||||
/** Update the clock port's media-time.
|
||||
*
|
||||
* @param port The clock port to update
|
||||
* @param media_time New media-time to be applied (microseconds)
|
||||
*
|
||||
* @return MMAL_SUCCESS on success
|
||||
*/
|
||||
MMAL_STATUS_T mmal_port_clock_media_time_set(MMAL_PORT_T *port, int64_t media_time);
|
||||
|
||||
/** Set an offset for the port's media-time.
|
||||
*
|
||||
* @param port The clock port to update
|
||||
* @param offset Media-time offset (microseconds)
|
||||
*
|
||||
* @return MMAL_SUCCESS on success
|
||||
*/
|
||||
MMAL_STATUS_T mmal_port_clock_media_time_offset_set(MMAL_PORT_T *port, int64_t offset);
|
||||
|
||||
/** Get the clock port's current media-time.
|
||||
* This takes the clock port's scale and media-time offset into account.
|
||||
*
|
||||
* @param port The clock port to query
|
||||
*
|
||||
* @return Current media-time in microseconds
|
||||
*/
|
||||
int64_t mmal_port_clock_media_time_get(MMAL_PORT_T *port);
|
||||
|
||||
/** Get the clock port's media-time offset.
|
||||
*
|
||||
* @param port The clock port to query
|
||||
*
|
||||
* @return Media-time offset in microseconds
|
||||
*/
|
||||
int64_t mmal_port_clock_media_time_offset_get(MMAL_PORT_T *port);
|
||||
|
||||
/** Set the clock port's scale.
|
||||
*
|
||||
* @param port The clock port
|
||||
* @param scale Scale factor in Q16 format
|
||||
*
|
||||
* @return MMAL_SUCCESS on success
|
||||
*/
|
||||
MMAL_STATUS_T mmal_port_clock_scale_set(MMAL_PORT_T *port, MMAL_RATIONAL_T scale);
|
||||
|
||||
/** Get the clock port's scale.
|
||||
*
|
||||
* @param port The clock port
|
||||
*
|
||||
* @return Current clock port scale factor
|
||||
*/
|
||||
MMAL_RATIONAL_T mmal_port_clock_scale_get(MMAL_PORT_T *port);
|
||||
|
||||
/** Get the clock port's state.
|
||||
*
|
||||
* @param port The clock port to query
|
||||
*
|
||||
* @return TRUE if clock port is active (i.e. local media-time is advancing)
|
||||
*/
|
||||
MMAL_BOOL_T mmal_port_clock_is_active(MMAL_PORT_T *port);
|
||||
|
||||
#endif /* MMAL_PORT_PRIVATE_H */
|
||||
|
||||
@@ -68,7 +68,9 @@ MMAL_QUEUE_T *mmal_queue_create(void)
|
||||
/** Put a MMAL_BUFFER_HEADER_T into a QUEUE */
|
||||
void mmal_queue_put(MMAL_QUEUE_T *queue, MMAL_BUFFER_HEADER_T *buffer)
|
||||
{
|
||||
vcos_mutex_lock(&queue->lock);
|
||||
if(!queue || !buffer) return;
|
||||
|
||||
vcos_mutex_lock(&queue->lock);
|
||||
queue->length++;
|
||||
*queue->last = buffer;
|
||||
buffer->next = 0;
|
||||
@@ -80,7 +82,9 @@ 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. */
|
||||
void mmal_queue_put_back(MMAL_QUEUE_T *queue, MMAL_BUFFER_HEADER_T *buffer)
|
||||
{
|
||||
vcos_mutex_lock(&queue->lock);
|
||||
if(!queue || !buffer) return;
|
||||
|
||||
vcos_mutex_lock(&queue->lock);
|
||||
queue->length++;
|
||||
buffer->next = queue->first;
|
||||
queue->first = buffer;
|
||||
@@ -94,6 +98,8 @@ 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)
|
||||
@@ -102,6 +108,7 @@ MMAL_BUFFER_HEADER_T *mmal_queue_get(MMAL_QUEUE_T *queue)
|
||||
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;
|
||||
@@ -116,7 +123,9 @@ MMAL_BUFFER_HEADER_T *mmal_queue_get(MMAL_QUEUE_T *queue)
|
||||
/** Wait for a MMAL_BUFFER_HEADER_T from a QUEUE. */
|
||||
MMAL_BUFFER_HEADER_T *mmal_queue_wait(MMAL_QUEUE_T *queue)
|
||||
{
|
||||
vcos_semaphore_wait(&queue->semaphore);
|
||||
if(!queue) return 0;
|
||||
|
||||
vcos_semaphore_wait(&queue->semaphore);
|
||||
vcos_semaphore_post(&queue->semaphore);
|
||||
return mmal_queue_get(queue);
|
||||
}
|
||||
@@ -124,7 +133,9 @@ MMAL_BUFFER_HEADER_T *mmal_queue_wait(MMAL_QUEUE_T *queue)
|
||||
/** Get the number of MMAL_BUFFER_HEADER_T currently in a QUEUE */
|
||||
unsigned int mmal_queue_length(MMAL_QUEUE_T *queue)
|
||||
{
|
||||
return queue->length;
|
||||
if(!queue) return 0;
|
||||
|
||||
return queue->length;
|
||||
}
|
||||
|
||||
/** Destroy a queue of MMAL_BUFFER_HEADER_T */
|
||||
|
||||
@@ -124,6 +124,10 @@ typedef struct MMAL_BUFFER_HEADER_T
|
||||
#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)
|
||||
/* @} */
|
||||
|
||||
/** \name Video buffer header flags
|
||||
@@ -150,14 +154,59 @@ typedef struct MMAL_BUFFER_HEADER_T
|
||||
*/
|
||||
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
|
||||
|
||||
98
interface/mmal/mmal_clock.h
Normal file
98
interface/mmal/mmal_clock.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef MMAL_CLOCK_H
|
||||
#define MMAL_CLOCK_H
|
||||
|
||||
#include "mmal_types.h"
|
||||
#include "mmal_common.h"
|
||||
|
||||
/** \defgroup MmalClock Clock Framework
|
||||
* The MMAL clock framework provides scheduling facilities to the rest of
|
||||
* MMAL.
|
||||
*
|
||||
* The framework consists mainly of clock ports and a clock module. Client
|
||||
* applications and components interact directly with clock ports, while
|
||||
* the clock module is only used internally by clock ports.
|
||||
*
|
||||
* Clock ports ensure that the local media-time for each component is
|
||||
* synchronised across all components. This is done by passing buffers between
|
||||
* clock ports which contain clock-specific data.
|
||||
*
|
||||
* One clock port will normally act as the reference clock for the rest of the
|
||||
* system. This is usually chosen to be the clock port of the audio render
|
||||
* component, but is configurable by the client and could potentially be any
|
||||
* other clock port (or even the client application itself).
|
||||
*
|
||||
* Components that are responsible for timed delivery of frames, do so by
|
||||
* registering callback requests for a particular time-stamp with the clock
|
||||
* port. These requests are scheduled using the clock module which maintains
|
||||
* an internal media-time.
|
||||
*
|
||||
* The clock framework also provides the ability to perform playback at different
|
||||
* speeds. This is achieved with a clock scale factor which determines the speed
|
||||
* at which the media-time advances relative to real-time, with:
|
||||
* scale = 1.0 -> normal playback speed
|
||||
* scale = 0 -> playback paused
|
||||
* scale > 1.0 -> fast-forward
|
||||
* scale < 1.0 -> slow motion
|
||||
*/
|
||||
|
||||
/** Clock payload magic */
|
||||
#define MMAL_CLOCK_PAYLOAD_MAGIC MMAL_FOURCC('C','K','L','M')
|
||||
|
||||
/** Clock reference update */
|
||||
#define MMAL_CLOCK_PAYLOAD_REFERENCE MMAL_FOURCC('C','R','E','F')
|
||||
|
||||
/** Clock state update */
|
||||
#define MMAL_CLOCK_PAYLOAD_ACTIVE MMAL_FOURCC('C','A','C','T')
|
||||
|
||||
/** Clock scale update */
|
||||
#define MMAL_CLOCK_PAYLOAD_SCALE MMAL_FOURCC('C','S','C','A')
|
||||
|
||||
/** Clock media-time update */
|
||||
#define MMAL_CLOCK_PAYLOAD_TIME MMAL_FOURCC('C','T','I','M')
|
||||
|
||||
/** Clock payload not valid */
|
||||
#define MMAL_CLOCK_PAYLOAD_INVALID 0
|
||||
|
||||
/** Clock buffer payload type used to pass data between clock ports
|
||||
* and for signalling a clock event to a client. */
|
||||
typedef struct MMAL_CLOCK_PAYLOAD_T
|
||||
{
|
||||
uint32_t id; /**< 4cc payload id */
|
||||
uint32_t magic; /**< 4cc payload magic */
|
||||
int64_t time; /**< media-time at which the event ocurred */
|
||||
union
|
||||
{
|
||||
MMAL_BOOL_T enable; /**< clock reference or clock active */
|
||||
MMAL_RATIONAL_T scale; /**< new clock scale */
|
||||
} data;
|
||||
} MMAL_CLOCK_PAYLOAD_T;
|
||||
|
||||
#endif /* MMAL_CLOCK_H */
|
||||
@@ -77,4 +77,7 @@ typedef struct MMAL_CORE_PORT_STATISTICS_T
|
||||
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 */
|
||||
|
||||
@@ -47,7 +47,7 @@ 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 container module in use */
|
||||
/** Pointer to the private data of the module in use */
|
||||
struct MMAL_COMPONENT_PRIVATE_T *priv;
|
||||
|
||||
/** Pointer to private data of the client */
|
||||
@@ -72,6 +72,12 @@ typedef struct MMAL_COMPONENT_T
|
||||
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;
|
||||
|
||||
@@ -61,7 +61,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#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')
|
||||
@@ -93,9 +101,106 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/** \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_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 */
|
||||
|
||||
@@ -59,6 +59,11 @@ typedef struct
|
||||
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.
|
||||
@@ -103,21 +108,32 @@ typedef union
|
||||
/* @} */
|
||||
|
||||
/** \name Undefined encoding value.
|
||||
* The value indicates an unknown encoding
|
||||
* \attention Should this be in the mmal_encodings.h file?
|
||||
* 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 */
|
||||
uint32_t encoding; /**< FourCC specifying the encoding 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 */
|
||||
|
||||
@@ -183,6 +199,7 @@ MMAL_STATUS_T mmal_format_full_copy(MMAL_ES_FORMAT_T *format_dest, MMAL_ES_FORMA
|
||||
#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 */
|
||||
/* @} */
|
||||
|
||||
@@ -38,19 +38,19 @@ extern VCOS_LOG_CAT_T mmal_log_category;
|
||||
|
||||
#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_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_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_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__)
|
||||
|
||||
@@ -31,12 +31,30 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#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
|
||||
{
|
||||
@@ -68,8 +86,21 @@ typedef struct MMAL_PARAMETER_BOOLEAN_T
|
||||
MMAL_BOOL_T enable; /**< Parameter value */
|
||||
} MMAL_PARAMETER_BOOLEAN_T;
|
||||
|
||||
/** Unsigned 16.16 fixed point value, also known as Q16.16 */
|
||||
typedef uint32_t MMAL_FIXED_16_16_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)
|
||||
@@ -134,6 +165,30 @@ typedef struct MMAL_PARAMETER_FRAME_RATE_T {
|
||||
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 */
|
||||
|
||||
64
interface/mmal/mmal_parameters_audio.h
Normal file
64
interface/mmal/mmal_parameters_audio.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef 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 */
|
||||
};
|
||||
|
||||
/** 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 */
|
||||
|
||||
@@ -38,14 +38,20 @@ All rights reserved.
|
||||
|
||||
#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 */
|
||||
@@ -58,13 +64,15 @@ enum {
|
||||
MMAL_PARAMETER_EXPOSURE_COMP, /**< Takes a @ref MMAL_PARAMETER_INT32_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_BOOLEAN_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 */
|
||||
@@ -74,6 +82,8 @@ enum {
|
||||
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 */
|
||||
@@ -82,6 +92,37 @@ enum {
|
||||
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 */
|
||||
};
|
||||
|
||||
/** Thumbnail configuration parameter type */
|
||||
@@ -120,6 +161,8 @@ typedef enum
|
||||
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;
|
||||
|
||||
@@ -135,6 +178,7 @@ 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;
|
||||
|
||||
@@ -178,6 +222,23 @@ typedef enum MMAL_PARAM_IMAGEFX_T
|
||||
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_MAX = 0x7fffffff
|
||||
} MMAL_PARAM_IMAGEFX_T;
|
||||
|
||||
@@ -188,6 +249,17 @@ typedef struct MMAL_PARAMETER_IMAGEFX_T
|
||||
MMAL_PARAM_IMAGEFX_T value; /**< Image effect mode */
|
||||
} MMAL_PARAMETER_IMAGEFX_T;
|
||||
|
||||
#define MMAL_MAX_IMAGEFX_PARAMETERS 5 /* 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
|
||||
{
|
||||
@@ -273,6 +345,11 @@ typedef enum MMAL_PARAM_FOCUS_T
|
||||
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;
|
||||
|
||||
@@ -283,6 +360,22 @@ typedef struct MMAL_PARAMETER_FOCUS_T
|
||||
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,
|
||||
@@ -290,6 +383,13 @@ typedef enum MMAL_PARAM_FOCUS_STATUS_T
|
||||
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;
|
||||
@@ -471,4 +571,87 @@ typedef struct MMAL_PARAMETER_FLASH_SELECT_T
|
||||
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;
|
||||
|
||||
#endif /* MMAL_PARAMETERS_CAMERA_H */
|
||||
|
||||
77
interface/mmal/mmal_parameters_clock.h
Normal file
77
interface/mmal/mmal_parameters_clock.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef MMAL_PARAMETERS_CLOCK_H
|
||||
#define MMAL_PARAMETERS_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_TIME_OFFSET, /**< 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 */
|
||||
};
|
||||
|
||||
/** Media-time update thresholds */
|
||||
typedef struct MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD_T
|
||||
{
|
||||
MMAL_PARAMETER_HEADER_T hdr;
|
||||
|
||||
/** 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_PARAMETER_CLOCK_UPDATE_THRESHOLD_T;
|
||||
|
||||
/** Media-time discontinuity settings */
|
||||
typedef struct MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD_T
|
||||
{
|
||||
MMAL_PARAMETER_HEADER_T hdr;
|
||||
|
||||
/** 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_PARAMETER_CLOCK_DISCONT_THRESHOLD_T;
|
||||
|
||||
#endif /* MMAL_PARAMETERS_CLOCK_H */
|
||||
@@ -45,6 +45,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#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)
|
||||
|
||||
|
||||
/**@}*/
|
||||
|
||||
@@ -62,6 +69,9 @@ enum {
|
||||
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 */
|
||||
};
|
||||
|
||||
/**@}*/
|
||||
@@ -104,6 +114,21 @@ typedef struct MMAL_PARAMETER_BUFFER_REQUIREMENTS_T
|
||||
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.
|
||||
@@ -125,7 +150,8 @@ typedef struct MMAL_PARAMETER_STATISTICS_T
|
||||
typedef enum
|
||||
{
|
||||
MMAL_CORE_STATS_RX,
|
||||
MMAL_CORE_STATS_TX
|
||||
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.
|
||||
@@ -148,5 +174,15 @@ typedef struct MMAL_PARAMETER_MEM_USAGE_T
|
||||
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 */
|
||||
|
||||
|
||||
@@ -30,6 +30,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "mmal_parameters_common.h"
|
||||
|
||||
/*************************************************
|
||||
* ALWAYS ADD NEW ENUMS AT THE END OF THIS LIST! *
|
||||
************************************************/
|
||||
|
||||
/** Video-specific MMAL parameter IDs.
|
||||
* @ingroup MMAL_PARAMETER_IDS
|
||||
*/
|
||||
@@ -49,14 +53,42 @@ enum {
|
||||
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_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. */
|
||||
};
|
||||
|
||||
/** Display transformations.
|
||||
@@ -205,6 +237,7 @@ typedef enum MMAL_VIDEO_PROFILE_T {
|
||||
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;
|
||||
|
||||
@@ -274,6 +307,34 @@ typedef enum MMAL_VIDEO_RATECONTROL_T {
|
||||
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;
|
||||
@@ -281,13 +342,26 @@ typedef struct MMAL_PARAMETER_VIDEO_RATECONTROL_T {
|
||||
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,
|
||||
MMAL_VIDEO_NALUNITFORMAT_NALUNITPERBUFFER,
|
||||
MMAL_VIDEO_NALUNITFORMAT_ONEBYTEINTERLEAVELENGTH,
|
||||
MMAL_VIDEO_NALUNITFORMAT_TWOBYTEINTERLEAVELENGTH,
|
||||
MMAL_VIDEO_NALUNITFORMAT_FOURBYTEINTERLEAVELENGTH,
|
||||
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;
|
||||
|
||||
@@ -309,6 +383,19 @@ typedef struct MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION_T {
|
||||
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;
|
||||
@@ -323,4 +410,26 @@ typedef struct MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE_T {
|
||||
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;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -148,6 +148,16 @@ typedef MMAL_BOOL_T (*MMAL_POOL_BH_CB_T)(MMAL_POOL_T *pool, MMAL_BUFFER_HEADER_T
|
||||
*/
|
||||
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
|
||||
|
||||
@@ -48,6 +48,7 @@ typedef enum
|
||||
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;
|
||||
@@ -81,7 +82,8 @@ typedef struct MMAL_PORT_T
|
||||
const char *name; /**< Port name. Used for debugging purposes (Read Only) */
|
||||
|
||||
MMAL_PORT_TYPE_T type; /**< Type of the port (Read Only) */
|
||||
uint32_t index; /**< Index 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 */
|
||||
|
||||
@@ -88,6 +88,9 @@ typedef struct
|
||||
#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
|
||||
|
||||
@@ -3,9 +3,11 @@ add_library (mmal_util
|
||||
mmal_util.c
|
||||
mmal_connection.c
|
||||
mmal_graph.c
|
||||
mmal_list.c
|
||||
mmal_param_convert.c
|
||||
mmal_util_params.c
|
||||
mmal_component_wrapper.c
|
||||
mmal_util_rational.c
|
||||
)
|
||||
|
||||
target_link_libraries (mmal_util vcos)
|
||||
|
||||
@@ -73,6 +73,7 @@ static MMAL_BOOL_T mmal_connection_bh_release_cb(MMAL_POOL_T *pool, MMAL_BUFFER_
|
||||
MMAL_CONNECTION_T *connection = (MMAL_CONNECTION_T *)userdata;
|
||||
MMAL_PARAM_UNUSED(pool);
|
||||
|
||||
/* Queue the buffer produced by the output port */
|
||||
mmal_queue_put(pool->queue, buffer);
|
||||
|
||||
if (connection->callback)
|
||||
@@ -140,7 +141,7 @@ MMAL_STATUS_T mmal_connection_create(MMAL_CONNECTION_T **cx,
|
||||
char *name;
|
||||
|
||||
/* Sanity checking */
|
||||
if (!cx || out->type != MMAL_PORT_TYPE_OUTPUT || in->type != MMAL_PORT_TYPE_INPUT)
|
||||
if (!cx)
|
||||
return MMAL_EINVAL;
|
||||
|
||||
private = vcos_malloc(size, "mmal connection");
|
||||
@@ -151,15 +152,11 @@ MMAL_STATUS_T mmal_connection_create(MMAL_CONNECTION_T **cx,
|
||||
private->refcount = 1;
|
||||
name = (char *)&private[1];
|
||||
|
||||
snprintf(name, name_size - 1, CONNECTION_NAME_FORMAT,
|
||||
vcos_snprintf(name, name_size - 1, CONNECTION_NAME_FORMAT,
|
||||
out->component->name,
|
||||
out->type == MMAL_PORT_TYPE_CONTROL ? "ctr" :
|
||||
out->type == MMAL_PORT_TYPE_INPUT ? "in" :
|
||||
out->type == MMAL_PORT_TYPE_OUTPUT ? "out" : "invalid", (int)out->index,
|
||||
mmal_port_type_to_string(out->type), (int)out->index,
|
||||
in->component->name,
|
||||
in->type == MMAL_PORT_TYPE_CONTROL ? "ctr" :
|
||||
in->type == MMAL_PORT_TYPE_INPUT ? "in" :
|
||||
in->type == MMAL_PORT_TYPE_OUTPUT ? "out" : "invalid", (int)in->index);
|
||||
mmal_port_type_to_string(in->type), (int)in->index);
|
||||
|
||||
LOG_TRACE("out %p, in %p, flags %x, %s", out, in, flags, name);
|
||||
|
||||
@@ -207,6 +204,10 @@ MMAL_STATUS_T mmal_connection_create(MMAL_CONNECTION_T **cx,
|
||||
|
||||
/* Create empty pool of buffer headers for now (will be resized later on) */
|
||||
private->pool_port = (in->capabilities & MMAL_PORT_CAPABILITY_ALLOCATION) ? in : out;
|
||||
if (flags & MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT)
|
||||
private->pool_port = in;
|
||||
if (flags & MMAL_CONNECTION_FLAG_ALLOCATION_ON_OUTPUT)
|
||||
private->pool_port = out;
|
||||
connection->pool = mmal_port_pool_create(private->pool_port, 0, 0);
|
||||
if (!connection->pool)
|
||||
goto error;
|
||||
@@ -222,7 +223,7 @@ MMAL_STATUS_T mmal_connection_create(MMAL_CONNECTION_T **cx,
|
||||
in->userdata = (void *)connection;
|
||||
connection->time_setup = vcos_getmicrosecs() - connection->time_setup;
|
||||
*cx = connection;
|
||||
return MMAL_SUCCESS;
|
||||
return status;
|
||||
|
||||
error:
|
||||
mmal_connection_destroy_internal(connection);
|
||||
@@ -287,7 +288,7 @@ MMAL_STATUS_T mmal_connection_enable(MMAL_CONNECTION_T *connection)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Set the buffering properties on both port */
|
||||
/* Set the buffering properties on both ports */
|
||||
buffer_num = MMAL_MAX(out->buffer_num, in->buffer_num);
|
||||
buffer_size = MMAL_MAX(out->buffer_size, in->buffer_size);
|
||||
out->buffer_num = in->buffer_num = buffer_num;
|
||||
@@ -324,6 +325,23 @@ MMAL_STATUS_T mmal_connection_enable(MMAL_CONNECTION_T *connection)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Clock ports need buffers to send clock updates, so
|
||||
* populate both connected clock ports */
|
||||
if ((out->type == MMAL_PORT_TYPE_CLOCK) && (in->type == MMAL_PORT_TYPE_CLOCK))
|
||||
{
|
||||
MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(connection->pool->queue);
|
||||
while (buffer)
|
||||
{
|
||||
mmal_port_send_buffer(out, buffer);
|
||||
buffer = mmal_queue_get(connection->pool->queue);
|
||||
if (buffer)
|
||||
{
|
||||
mmal_port_send_buffer(in, buffer);
|
||||
buffer = mmal_queue_get(connection->pool->queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
connection->time_enable = vcos_getmicrosecs() - connection->time_enable;
|
||||
connection->is_enabled = status == MMAL_SUCCESS;
|
||||
|
||||
@@ -90,6 +90,10 @@ extern "C" {
|
||||
/** 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 */
|
||||
|
||||
@@ -35,9 +35,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define GRAPH_CONNECTIONS_MAX 16
|
||||
|
||||
/*****************************************************************************/
|
||||
struct MMAL_GRAPH_T
|
||||
{
|
||||
};
|
||||
|
||||
/** Private context for our graph.
|
||||
* This also acts as a MMAL_COMPONENT_MODULE_T for when components are instantiated from graphs */
|
||||
@@ -127,26 +124,27 @@ static void graph_stop_worker_thread(MMAL_GRAPH_PRIVATE_T *graph)
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
MMAL_STATUS_T mmal_graph_create(MMAL_GRAPH_T **graph)
|
||||
MMAL_STATUS_T mmal_graph_create(MMAL_GRAPH_T **graph, unsigned int userdata_size)
|
||||
{
|
||||
unsigned int size = sizeof(MMAL_GRAPH_PRIVATE_T);
|
||||
MMAL_GRAPH_PRIVATE_T *private;
|
||||
|
||||
LOG_TRACE("graph %p", graph);
|
||||
LOG_TRACE("graph %p, userdata_size %u", graph, userdata_size);
|
||||
|
||||
/* Sanity checking */
|
||||
if (!graph)
|
||||
return MMAL_EINVAL;
|
||||
|
||||
private = vcos_malloc(size, "mmal connection graph");
|
||||
private = vcos_calloc(1, sizeof(MMAL_GRAPH_PRIVATE_T) + userdata_size, "mmal connection graph");
|
||||
if (!private)
|
||||
return MMAL_ENOMEM;
|
||||
memset(private, 0, size);
|
||||
*graph = &private->graph;
|
||||
if (userdata_size)
|
||||
(*graph)->userdata = (struct MMAL_GRAPH_USERDATA_T *)&private[1];
|
||||
|
||||
if (vcos_semaphore_create(&private->sema, "mmal graph sema", 0) != VCOS_SUCCESS)
|
||||
{
|
||||
LOG_ERROR("failed to create semaphore %p", graph);
|
||||
vcos_free(private);
|
||||
return MMAL_ENOSPC;
|
||||
}
|
||||
|
||||
@@ -159,14 +157,21 @@ MMAL_STATUS_T mmal_graph_destroy(MMAL_GRAPH_T *graph)
|
||||
unsigned i;
|
||||
MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
|
||||
|
||||
if (!graph)
|
||||
return MMAL_EINVAL;
|
||||
|
||||
LOG_TRACE("%p", graph);
|
||||
|
||||
for (i = 0; i < private->component_num; i++)
|
||||
mmal_component_release(private->component[i]);
|
||||
/* Notify client of destruction */
|
||||
if (graph->pf_destroy)
|
||||
graph->pf_destroy(graph);
|
||||
|
||||
for (i = 0; i < private->connection_num; i++)
|
||||
mmal_connection_release(private->connection[i]);
|
||||
|
||||
for (i = 0; i < private->component_num; i++)
|
||||
mmal_component_release(private->component[i]);
|
||||
|
||||
vcos_semaphore_delete(&private->sema);
|
||||
|
||||
vcos_free(graph);
|
||||
@@ -558,7 +563,8 @@ static MMAL_PORT_T *find_port_to_graph(MMAL_GRAPH_PRIVATE_T *graph, MMAL_PORT_T
|
||||
return port->type == MMAL_PORT_TYPE_INPUT ? component->input[i] : component->output[i];
|
||||
}
|
||||
|
||||
static MMAL_STATUS_T graph_port_update(MMAL_GRAPH_PRIVATE_T *graph, MMAL_PORT_T *graph_port)
|
||||
static MMAL_STATUS_T graph_port_update(MMAL_GRAPH_PRIVATE_T *graph,
|
||||
MMAL_PORT_T *graph_port, MMAL_BOOL_T init)
|
||||
{
|
||||
MMAL_STATUS_T status;
|
||||
MMAL_PORT_T *port;
|
||||
@@ -579,13 +585,15 @@ static MMAL_STATUS_T graph_port_update(MMAL_GRAPH_PRIVATE_T *graph, MMAL_PORT_T
|
||||
|
||||
graph_port->buffer_num_min = port->buffer_num_min;
|
||||
graph_port->buffer_num_recommended = port->buffer_num_recommended;
|
||||
graph_port->buffer_num = port->buffer_num;
|
||||
graph_port->buffer_size_min = port->buffer_size_min;
|
||||
graph_port->buffer_size_recommended = port->buffer_size_recommended;
|
||||
graph_port->buffer_size = port->buffer_size;
|
||||
graph_port->is_enabled = port->is_enabled;
|
||||
graph_port->buffer_alignment_min = port->buffer_alignment_min;
|
||||
graph_port->capabilities = port->capabilities;
|
||||
if (init)
|
||||
{
|
||||
graph_port->buffer_num = port->buffer_num;
|
||||
graph_port->buffer_size = port->buffer_size;
|
||||
}
|
||||
return MMAL_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -613,12 +621,19 @@ static MMAL_STATUS_T graph_port_update_requirements(MMAL_GRAPH_PRIVATE_T *graph,
|
||||
static MMAL_STATUS_T graph_component_destroy(MMAL_COMPONENT_T *component)
|
||||
{
|
||||
MMAL_COMPONENT_MODULE_T *graph = component->priv->module;
|
||||
if(component->input_num)
|
||||
|
||||
/* Notify client of destruction */
|
||||
if (graph->graph.pf_destroy)
|
||||
graph->graph.pf_destroy(&graph->graph);
|
||||
graph->graph.pf_destroy = NULL;
|
||||
|
||||
if (component->input_num)
|
||||
mmal_ports_free(component->input, component->input_num);
|
||||
|
||||
if(component->output_num)
|
||||
if (component->output_num)
|
||||
mmal_ports_free(component->output, component->output_num);
|
||||
|
||||
/* coverity[address_free] Freeing the first item in the structure is safe */
|
||||
mmal_graph_destroy(&graph->graph);
|
||||
return MMAL_SUCCESS;
|
||||
}
|
||||
@@ -640,10 +655,11 @@ static MMAL_STATUS_T graph_component_disable(MMAL_COMPONENT_T *component)
|
||||
/** Callback given to mmal_port_enable() */
|
||||
static void graph_port_enable_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
|
||||
{
|
||||
MMAL_GRAPH_PRIVATE_T *graph = (MMAL_GRAPH_PRIVATE_T *)port->userdata;
|
||||
MMAL_GRAPH_PRIVATE_T *graph_private = (MMAL_GRAPH_PRIVATE_T *)port->userdata;
|
||||
MMAL_PORT_T *graph_port;
|
||||
MMAL_STATUS_T status;
|
||||
|
||||
graph_port = find_port_to_graph(graph, port);
|
||||
graph_port = find_port_to_graph(graph_private, port);
|
||||
if (!graph_port)
|
||||
{
|
||||
vcos_assert(0);
|
||||
@@ -651,6 +667,14 @@ static void graph_port_enable_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer
|
||||
return;
|
||||
}
|
||||
|
||||
/* Call user defined function first */
|
||||
if (graph_private->graph.pf_return_buffer)
|
||||
{
|
||||
status = graph_private->graph.pf_return_buffer(&graph_private->graph, graph_port, buffer);
|
||||
if (status != MMAL_ENOSYS)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Forward the callback */
|
||||
if (buffer->cmd)
|
||||
mmal_port_event_send(graph_port, buffer);
|
||||
@@ -664,23 +688,31 @@ static MMAL_STATUS_T graph_port_state_propagate(MMAL_GRAPH_PRIVATE_T *graph,
|
||||
{
|
||||
MMAL_COMPONENT_T *component = port->component;
|
||||
MMAL_STATUS_T status = MMAL_SUCCESS;
|
||||
MMAL_PORT_TYPE_T type = port->type;
|
||||
unsigned int i, j;
|
||||
|
||||
LOG_TRACE("graph: %p, port %s(%p)", graph, port->name, port);
|
||||
|
||||
if (port->type == MMAL_PORT_TYPE_OUTPUT)
|
||||
return MMAL_SUCCESS; /* Nothing to do */
|
||||
type = MMAL_PORT_TYPE_INPUT;
|
||||
if (port->type == MMAL_PORT_TYPE_INPUT)
|
||||
type = MMAL_PORT_TYPE_OUTPUT;
|
||||
|
||||
/* Loop through all the output ports of the component and if they are not enabled and
|
||||
* match one of the connections we maintain, then we need to propagate the port enable. */
|
||||
for (i = 0; i < component->output_num; i++)
|
||||
for (i = 0; i < component->port_num; i++)
|
||||
{
|
||||
if (!!component->output[i]->is_enabled == !!enable)
|
||||
if (component->port[i]->type != type)
|
||||
continue;
|
||||
|
||||
if ((component->port[i]->is_enabled && enable) ||
|
||||
(!component->port[i]->is_enabled && !enable))
|
||||
continue;
|
||||
|
||||
/* Find the matching connection */
|
||||
for (j = 0; j < graph->connection_num; j++)
|
||||
if (graph->connection[j]->out == component->output[i])
|
||||
if (graph->connection[j]->out == component->port[i] ||
|
||||
graph->connection[j]->in == component->port[i])
|
||||
break;
|
||||
|
||||
if (j == graph->connection_num)
|
||||
@@ -696,7 +728,8 @@ static MMAL_STATUS_T graph_port_state_propagate(MMAL_GRAPH_PRIVATE_T *graph,
|
||||
mmal_log_dump_port(graph->connection[j]->in);
|
||||
}
|
||||
|
||||
status = graph_port_state_propagate(graph, graph->connection[j]->in, enable);
|
||||
status = graph_port_state_propagate(graph, graph->connection[j]->in == component->port[i] ?
|
||||
graph->connection[j]->out : graph->connection[j]->in, enable);
|
||||
if (status != MMAL_SUCCESS)
|
||||
break;
|
||||
|
||||
@@ -714,12 +747,12 @@ static MMAL_STATUS_T graph_port_state_propagate(MMAL_GRAPH_PRIVATE_T *graph,
|
||||
/** Enable processing on a port */
|
||||
static MMAL_STATUS_T graph_port_enable(MMAL_PORT_T *graph_port, MMAL_PORT_BH_CB_T cb)
|
||||
{
|
||||
MMAL_GRAPH_PRIVATE_T *graph = graph_port->component->priv->module;
|
||||
MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
|
||||
MMAL_PORT_T *port;
|
||||
MMAL_STATUS_T status;
|
||||
MMAL_PARAM_UNUSED(cb);
|
||||
|
||||
port = find_port_from_graph(graph, graph_port);
|
||||
port = find_port_from_graph(graph_private, graph_port);
|
||||
if (!port)
|
||||
return MMAL_EINVAL;
|
||||
|
||||
@@ -728,60 +761,138 @@ static MMAL_STATUS_T graph_port_enable(MMAL_PORT_T *graph_port, MMAL_PORT_BH_CB_
|
||||
port->buffer_size = graph_port->buffer_size;
|
||||
|
||||
/* We'll intercept the callback */
|
||||
port->userdata = (void *)graph;
|
||||
port->userdata = (void *)graph_private;
|
||||
status = mmal_port_enable(port, graph_port_enable_cb);
|
||||
if (status != MMAL_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* We need to enable all the connected connections */
|
||||
status = graph_port_state_propagate(graph, port, 1);
|
||||
status = graph_port_state_propagate(graph_private, port, 1);
|
||||
|
||||
mmal_component_action_trigger(graph_port->component);
|
||||
return status;
|
||||
}
|
||||
|
||||
/** Disable processing on a port */
|
||||
static MMAL_STATUS_T graph_port_disable(MMAL_PORT_T *graph_port)
|
||||
{
|
||||
MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
|
||||
MMAL_PORT_T *port;
|
||||
|
||||
port = find_port_from_graph(graph_port->component->priv->module, graph_port);
|
||||
if (!port)
|
||||
return MMAL_EINVAL;
|
||||
|
||||
/* We need to disable all the connected connections.
|
||||
* Since disable does an implicit flush, we only want to do that if
|
||||
* we're acting on an input port or we risk discarding buffers along
|
||||
* the way. */
|
||||
if (!graph_private->input_num || port->type == MMAL_PORT_TYPE_INPUT)
|
||||
{
|
||||
MMAL_STATUS_T status = graph_port_state_propagate(graph_private, port, 0);
|
||||
if (status != MMAL_SUCCESS)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Forward the call */
|
||||
return mmal_port_disable(port);
|
||||
}
|
||||
|
||||
/** Propagate a port flush */
|
||||
static MMAL_STATUS_T graph_port_flush_propagate(MMAL_GRAPH_PRIVATE_T *graph,
|
||||
MMAL_PORT_T *port)
|
||||
{
|
||||
MMAL_COMPONENT_T *component = port->component;
|
||||
MMAL_STATUS_T status;
|
||||
unsigned int i, j;
|
||||
|
||||
LOG_TRACE("graph: %p, port %s(%p)", graph, port->name, port);
|
||||
|
||||
status = mmal_port_flush(port);
|
||||
if (status != MMAL_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (port->type == MMAL_PORT_TYPE_OUTPUT)
|
||||
return MMAL_SUCCESS;
|
||||
|
||||
/* Loop through all the output ports of the component and if they match one
|
||||
* of the connections we maintain, then we need to propagate the flush. */
|
||||
for (i = 0; i < component->port_num; i++)
|
||||
{
|
||||
if (component->port[i]->type != MMAL_PORT_TYPE_OUTPUT)
|
||||
continue;
|
||||
if (!component->port[i]->is_enabled)
|
||||
continue;
|
||||
|
||||
/* Find the matching connection */
|
||||
for (j = 0; j < graph->connection_num; j++)
|
||||
if (graph->connection[j]->out == component->port[i])
|
||||
break;
|
||||
|
||||
if (j == graph->connection_num)
|
||||
continue; /* No match */
|
||||
|
||||
/* Flush any buffer waiting in the connection queue */
|
||||
if (graph->connection[j]->queue)
|
||||
{
|
||||
MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(graph->connection[j]->queue);
|
||||
while(buffer)
|
||||
{
|
||||
mmal_buffer_header_release(buffer);
|
||||
buffer = mmal_queue_get(graph->connection[j]->queue);
|
||||
}
|
||||
}
|
||||
|
||||
status = graph_port_flush_propagate(graph, graph->connection[j]->in);
|
||||
if (status != MMAL_SUCCESS)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/** Flush a port */
|
||||
static MMAL_STATUS_T graph_port_flush(MMAL_PORT_T *graph_port)
|
||||
{
|
||||
MMAL_PORT_T *port;
|
||||
|
||||
port = find_port_from_graph(graph_port->component->priv->module, graph_port);
|
||||
if (!port)
|
||||
return MMAL_EINVAL;
|
||||
|
||||
/* Forward the call */
|
||||
return mmal_port_flush(port);
|
||||
}
|
||||
|
||||
/** Disable processing on a port */
|
||||
static MMAL_STATUS_T graph_port_disable(MMAL_PORT_T *graph_port)
|
||||
{
|
||||
MMAL_GRAPH_PRIVATE_T *graph = graph_port->component->priv->module;
|
||||
MMAL_PORT_T *port;
|
||||
MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
|
||||
MMAL_STATUS_T status;
|
||||
MMAL_PORT_T *port;
|
||||
|
||||
port = find_port_from_graph(graph_port->component->priv->module, graph_port);
|
||||
port = find_port_from_graph(graph_private, graph_port);
|
||||
if (!port)
|
||||
return MMAL_EINVAL;
|
||||
|
||||
/* We need to disable all the connected connections */
|
||||
status = graph_port_state_propagate(graph, port, 0);
|
||||
if (status != MMAL_SUCCESS)
|
||||
return status;
|
||||
/* Call user defined function first */
|
||||
if (graph_private->graph.pf_flush)
|
||||
{
|
||||
status = graph_private->graph.pf_flush(&graph_private->graph, graph_port);
|
||||
if (status != MMAL_ENOSYS)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Forward the call */
|
||||
return mmal_port_disable(port);
|
||||
return graph_port_flush_propagate(graph_private, port);
|
||||
}
|
||||
|
||||
/** Send a buffer header to a port */
|
||||
static MMAL_STATUS_T graph_port_send(MMAL_PORT_T *graph_port, MMAL_BUFFER_HEADER_T *buffer)
|
||||
{
|
||||
MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
|
||||
MMAL_STATUS_T status;
|
||||
MMAL_PORT_T *port;
|
||||
|
||||
port = find_port_from_graph(graph_port->component->priv->module, graph_port);
|
||||
if (!port)
|
||||
return MMAL_EINVAL;
|
||||
|
||||
/* Call user defined function first */
|
||||
if (graph_private->graph.pf_send_buffer)
|
||||
{
|
||||
status = graph_private->graph.pf_send_buffer(&graph_private->graph, graph_port, buffer);
|
||||
if (status != MMAL_ENOSYS)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Forward the call */
|
||||
return mmal_port_send_buffer(port, buffer);
|
||||
}
|
||||
@@ -841,12 +952,22 @@ static MMAL_STATUS_T graph_port_format_commit_propagate(MMAL_GRAPH_PRIVATE_T *gr
|
||||
/** Set format on a port */
|
||||
static MMAL_STATUS_T graph_port_format_commit(MMAL_PORT_T *graph_port)
|
||||
{
|
||||
MMAL_GRAPH_PRIVATE_T *graph = graph_port->component->priv->module;
|
||||
MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
|
||||
MMAL_STATUS_T status;
|
||||
MMAL_PORT_T *port;
|
||||
unsigned int i;
|
||||
|
||||
port = find_port_from_graph(graph, graph_port);
|
||||
/* Call user defined function first */
|
||||
if (graph_private->graph.pf_format_commit)
|
||||
{
|
||||
status = graph_private->graph.pf_format_commit(&graph_private->graph, graph_port);
|
||||
if (status == MMAL_SUCCESS)
|
||||
goto end;
|
||||
if (status != MMAL_ENOSYS)
|
||||
return status;
|
||||
}
|
||||
|
||||
port = find_port_from_graph(graph_private, graph_port);
|
||||
if (!port)
|
||||
return MMAL_EINVAL;
|
||||
|
||||
@@ -863,24 +984,25 @@ static MMAL_STATUS_T graph_port_format_commit(MMAL_PORT_T *graph_port)
|
||||
return status;
|
||||
|
||||
/* Propagate format changes to the connections */
|
||||
status = graph_port_format_commit_propagate(graph, port);
|
||||
status = graph_port_format_commit_propagate(graph_private, port);
|
||||
if (status != MMAL_SUCCESS)
|
||||
{
|
||||
LOG_ERROR("couldn't propagate format commit of port %s(%p)", port->name, port);
|
||||
return status;
|
||||
}
|
||||
|
||||
end:
|
||||
/* Read the values back */
|
||||
status = graph_port_update(graph, graph_port);
|
||||
status = graph_port_update(graph_private, graph_port, MMAL_FALSE);
|
||||
if (status != MMAL_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* Get the settings for the output ports in case they have changed */
|
||||
if (graph_port->type == MMAL_PORT_TYPE_INPUT)
|
||||
{
|
||||
for (i = 0; i < graph->output_num; i++)
|
||||
for (i = 0; i < graph_private->output_num; i++)
|
||||
{
|
||||
status = graph_port_update(graph, graph_port->component->output[i]);
|
||||
status = graph_port_update(graph_private, graph_port->component->output[i], MMAL_FALSE);
|
||||
if (status != MMAL_SUCCESS)
|
||||
return status;
|
||||
}
|
||||
@@ -889,12 +1011,44 @@ static MMAL_STATUS_T graph_port_format_commit(MMAL_PORT_T *graph_port)
|
||||
return MMAL_SUCCESS;
|
||||
}
|
||||
|
||||
static MMAL_STATUS_T graph_port_control_parameter_get(MMAL_PORT_T *graph_port,
|
||||
MMAL_PARAMETER_HEADER_T *param)
|
||||
{
|
||||
MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
|
||||
MMAL_STATUS_T status = MMAL_ENOSYS;
|
||||
unsigned int i;
|
||||
|
||||
/* Call user defined function first */
|
||||
if (graph_private->graph.pf_parameter_get)
|
||||
{
|
||||
status = graph_private->graph.pf_parameter_get(&graph_private->graph, graph_port, param);
|
||||
if (status != MMAL_ENOSYS)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* By default we do a get parameter on each component until one succeeds */
|
||||
for (i = 0; i < graph_private->component_num && status != MMAL_SUCCESS; i++)
|
||||
status = mmal_port_parameter_get(graph_private->component[i]->control, param);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static MMAL_STATUS_T graph_port_parameter_get(MMAL_PORT_T *graph_port,
|
||||
MMAL_PARAMETER_HEADER_T *param)
|
||||
{
|
||||
MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
|
||||
MMAL_STATUS_T status;
|
||||
MMAL_PORT_T *port;
|
||||
|
||||
port = find_port_from_graph(graph_port->component->priv->module, graph_port);
|
||||
/* Call user defined function first */
|
||||
if (graph_private->graph.pf_parameter_get)
|
||||
{
|
||||
status = graph_private->graph.pf_parameter_get(&graph_private->graph, graph_port, param);
|
||||
if (status != MMAL_ENOSYS)
|
||||
return status;
|
||||
}
|
||||
|
||||
port = find_port_from_graph(graph_private, graph_port);
|
||||
if (!port)
|
||||
return MMAL_EINVAL;
|
||||
|
||||
@@ -902,14 +1056,44 @@ static MMAL_STATUS_T graph_port_parameter_get(MMAL_PORT_T *graph_port,
|
||||
return mmal_port_parameter_get(port, param);
|
||||
}
|
||||
|
||||
static MMAL_STATUS_T graph_port_control_parameter_set(MMAL_PORT_T *graph_port,
|
||||
const MMAL_PARAMETER_HEADER_T *param)
|
||||
{
|
||||
MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
|
||||
MMAL_STATUS_T status = MMAL_ENOSYS;
|
||||
unsigned int i;
|
||||
|
||||
/* Call user defined function first */
|
||||
if (graph_private->graph.pf_parameter_set)
|
||||
{
|
||||
status = graph_private->graph.pf_parameter_set(&graph_private->graph, graph_port, param);
|
||||
if (status != MMAL_ENOSYS)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* By default we do a set parameter on each component until one succeeds */
|
||||
for (i = 0; i < graph_private->component_num && status != MMAL_SUCCESS; i++)
|
||||
status = mmal_port_parameter_set(graph_private->component[i]->control, param);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static MMAL_STATUS_T graph_port_parameter_set(MMAL_PORT_T *graph_port,
|
||||
const MMAL_PARAMETER_HEADER_T *param)
|
||||
{
|
||||
MMAL_GRAPH_PRIVATE_T *graph = graph_port->component->priv->module;
|
||||
MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
|
||||
MMAL_STATUS_T status;
|
||||
MMAL_PORT_T *port;
|
||||
|
||||
port = find_port_from_graph(graph, graph_port);
|
||||
/* Call user defined function first */
|
||||
if (graph_private->graph.pf_parameter_set)
|
||||
{
|
||||
status = graph_private->graph.pf_parameter_set(&graph_private->graph, graph_port, param);
|
||||
if (status != MMAL_ENOSYS)
|
||||
return status;
|
||||
}
|
||||
|
||||
port = find_port_from_graph(graph_private, graph_port);
|
||||
if (!port)
|
||||
return MMAL_EINVAL;
|
||||
|
||||
@@ -924,9 +1108,9 @@ static MMAL_STATUS_T graph_port_parameter_set(MMAL_PORT_T *graph_port,
|
||||
MMAL_COMPONENT_T *component = graph_port->component;
|
||||
unsigned int i;
|
||||
for (i = 0; status == MMAL_SUCCESS && i < component->input_num; i++)
|
||||
status = graph_port_update_requirements(graph, component->input[i]);
|
||||
status = graph_port_update_requirements(graph_private, component->input[i]);
|
||||
for (i = 0; status == MMAL_SUCCESS && i < component->output_num; i++)
|
||||
status = graph_port_update_requirements(graph, component->output[i]);
|
||||
status = graph_port_update_requirements(graph_private, component->output[i]);
|
||||
}
|
||||
|
||||
end:
|
||||
@@ -949,24 +1133,46 @@ static MMAL_STATUS_T graph_port_connect(MMAL_PORT_T *graph_port, MMAL_PORT_T *ot
|
||||
|
||||
static uint8_t *graph_port_payload_alloc(MMAL_PORT_T *graph_port, uint32_t payload_size)
|
||||
{
|
||||
MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
|
||||
MMAL_STATUS_T status;
|
||||
MMAL_PORT_T *port;
|
||||
uint8_t *payload;
|
||||
|
||||
port = find_port_from_graph(graph_port->component->priv->module, graph_port);
|
||||
if (!port)
|
||||
return 0;
|
||||
|
||||
/* Call user defined function first */
|
||||
if (graph_private->graph.pf_payload_alloc)
|
||||
{
|
||||
status = graph_private->graph.pf_payload_alloc(&graph_private->graph, graph_port,
|
||||
payload_size, &payload);
|
||||
if (status != MMAL_ENOSYS)
|
||||
return status == MMAL_SUCCESS ? payload : NULL;
|
||||
}
|
||||
|
||||
/* Forward the call */
|
||||
return mmal_port_payload_alloc(port, payload_size);
|
||||
}
|
||||
|
||||
static void graph_port_payload_free(MMAL_PORT_T *graph_port, uint8_t *payload)
|
||||
{
|
||||
MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
|
||||
MMAL_STATUS_T status;
|
||||
MMAL_PORT_T *port;
|
||||
|
||||
port = find_port_from_graph(graph_port->component->priv->module, graph_port);
|
||||
if (!port)
|
||||
return;
|
||||
|
||||
/* Call user defined function first */
|
||||
if (graph_private->graph.pf_payload_free)
|
||||
{
|
||||
status = graph_private->graph.pf_payload_free(&graph_private->graph, graph_port, payload);
|
||||
if (status == MMAL_SUCCESS)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Forward the call */
|
||||
mmal_port_payload_free(port, payload);
|
||||
}
|
||||
@@ -980,10 +1186,16 @@ static MMAL_STATUS_T mmal_component_create_from_graph(const char *name, MMAL_COM
|
||||
unsigned int i;
|
||||
MMAL_PARAM_UNUSED(name);
|
||||
|
||||
component->control->priv->pf_parameter_get = graph_port_control_parameter_get;
|
||||
component->control->priv->pf_parameter_set = graph_port_control_parameter_set;
|
||||
|
||||
/* Allocate the ports for this component */
|
||||
component->input = mmal_ports_alloc(component, graph->input_num, MMAL_PORT_TYPE_INPUT, 0);
|
||||
if(!component->input)
|
||||
goto error;
|
||||
if(graph->input_num)
|
||||
{
|
||||
component->input = mmal_ports_alloc(component, graph->input_num, MMAL_PORT_TYPE_INPUT, 0);
|
||||
if(!component->input)
|
||||
goto error;
|
||||
}
|
||||
component->input_num = graph->input_num;
|
||||
for(i = 0; i < component->input_num; i++)
|
||||
{
|
||||
@@ -996,19 +1208,20 @@ static MMAL_STATUS_T mmal_component_create_from_graph(const char *name, MMAL_COM
|
||||
component->input[i]->priv->pf_parameter_set = graph_port_parameter_set;
|
||||
if (graph->input[i]->priv->pf_connect && 0 /* FIXME: disabled for now */)
|
||||
component->input[i]->priv->pf_connect = graph_port_connect;
|
||||
if (graph->input[i]->priv->pf_payload_alloc)
|
||||
component->input[i]->priv->pf_payload_alloc = graph_port_payload_alloc;
|
||||
if (graph->input[i]->priv->pf_payload_free)
|
||||
component->input[i]->priv->pf_payload_free = graph_port_payload_free;
|
||||
component->input[i]->priv->pf_payload_alloc = graph_port_payload_alloc;
|
||||
component->input[i]->priv->pf_payload_free = graph_port_payload_free;
|
||||
|
||||
/* Mirror the port values */
|
||||
status = graph_port_update(graph, component->input[i]);
|
||||
status = graph_port_update(graph, component->input[i], MMAL_TRUE);
|
||||
if (status != MMAL_SUCCESS)
|
||||
goto error;
|
||||
}
|
||||
component->output = mmal_ports_alloc(component, graph->output_num, MMAL_PORT_TYPE_OUTPUT, 0);
|
||||
if(!component->output)
|
||||
goto error;
|
||||
if(graph->output_num)
|
||||
{
|
||||
component->output = mmal_ports_alloc(component, graph->output_num, MMAL_PORT_TYPE_OUTPUT, 0);
|
||||
if(!component->output)
|
||||
goto error;
|
||||
}
|
||||
component->output_num = graph->output_num;
|
||||
for(i = 0; i < component->output_num; i++)
|
||||
{
|
||||
@@ -1021,13 +1234,11 @@ static MMAL_STATUS_T mmal_component_create_from_graph(const char *name, MMAL_COM
|
||||
component->output[i]->priv->pf_parameter_set = graph_port_parameter_set;
|
||||
if (graph->output[i]->priv->pf_connect && 0 /* FIXME: disabled for now */)
|
||||
component->output[i]->priv->pf_connect = graph_port_connect;
|
||||
if (graph->output[i]->priv->pf_payload_alloc)
|
||||
component->output[i]->priv->pf_payload_alloc = graph_port_payload_alloc;
|
||||
if (graph->output[i]->priv->pf_payload_free)
|
||||
component->output[i]->priv->pf_payload_free = graph_port_payload_free;
|
||||
component->output[i]->priv->pf_payload_alloc = graph_port_payload_alloc;
|
||||
component->output[i]->priv->pf_payload_free = graph_port_payload_free;
|
||||
|
||||
/* Mirror the port values */
|
||||
status = graph_port_update(graph, component->output[i]);
|
||||
status = graph_port_update(graph, component->output[i], MMAL_TRUE);
|
||||
if (status != MMAL_SUCCESS)
|
||||
goto error;
|
||||
}
|
||||
@@ -1076,7 +1287,7 @@ MMAL_PORT_T *mmal_graph_find_port(MMAL_GRAPH_T *graph,
|
||||
for (i=0; i<private->component_num; i++)
|
||||
{
|
||||
MMAL_COMPONENT_T *comp = private->component[i];
|
||||
if (strcasecmp(name, comp->name) == 0)
|
||||
if (vcos_strcasecmp(name, comp->name) == 0)
|
||||
{
|
||||
unsigned num;
|
||||
MMAL_PORT_T **ports;
|
||||
|
||||
@@ -42,15 +42,41 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/** Structure describing a graph */
|
||||
typedef struct MMAL_GRAPH_T MMAL_GRAPH_T;
|
||||
typedef struct MMAL_GRAPH_T
|
||||
{
|
||||
/** Pointer to private data of the client */
|
||||
struct MMAL_GRAPH_USERDATA_T *userdata;
|
||||
|
||||
/** Optional callback that the client can set to get notified when the graph is going to be destroyed */
|
||||
void (*pf_destroy)(struct MMAL_GRAPH_T *);
|
||||
|
||||
/** Optional callback that the client can set to intercept parameter requests on ports exposed by the graph */
|
||||
MMAL_STATUS_T (*pf_parameter_set)(struct MMAL_GRAPH_T *, MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param);
|
||||
/** Optional callback that the client can set to intercept parameter requests on ports exposed by the graph */
|
||||
MMAL_STATUS_T (*pf_parameter_get)(struct MMAL_GRAPH_T *, MMAL_PORT_T *port, MMAL_PARAMETER_HEADER_T *param);
|
||||
/** Optional callback that the client can set to intercept format commit calls on ports exposed by the graph */
|
||||
MMAL_STATUS_T (*pf_format_commit)(struct MMAL_GRAPH_T *, MMAL_PORT_T *port);
|
||||
/** Optional callback that the client can set to intercept send buffer calls on ports exposed by the graph */
|
||||
MMAL_STATUS_T (*pf_send_buffer)(struct MMAL_GRAPH_T *, MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
|
||||
/** Optional callback that the client can set to intercept buffer callbacks on ports exposed by the graph */
|
||||
MMAL_STATUS_T (*pf_return_buffer)(struct MMAL_GRAPH_T *, MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
|
||||
/** Optional callback that the client can set to intercept payload alloc calls on ports exposed by the graph */
|
||||
MMAL_STATUS_T (*pf_payload_alloc)(struct MMAL_GRAPH_T *, MMAL_PORT_T *port, uint32_t payload_size, uint8_t **);
|
||||
/** Optional callback that the client can set to intercept payload free calls on ports exposed by the graph */
|
||||
MMAL_STATUS_T (*pf_payload_free)(struct MMAL_GRAPH_T *, MMAL_PORT_T *port, uint8_t *payload);
|
||||
/** Optional callback that the client can set to intercept flush calls on ports exposed by the graph */
|
||||
MMAL_STATUS_T (*pf_flush)(struct MMAL_GRAPH_T *, MMAL_PORT_T *port);
|
||||
|
||||
} MMAL_GRAPH_T;
|
||||
|
||||
/** Create an instance of a graph.
|
||||
* The newly created graph will need to be populated by the client.
|
||||
*
|
||||
* @param graph returned graph
|
||||
* @param userdata_size size to be allocated for the userdata field
|
||||
* @return MMAL_SUCCESS on success
|
||||
*/
|
||||
MMAL_STATUS_T mmal_graph_create(MMAL_GRAPH_T **graph);
|
||||
MMAL_STATUS_T mmal_graph_create(MMAL_GRAPH_T **graph, unsigned int userdata_size);
|
||||
|
||||
/** Add a component to a graph.
|
||||
* Allows the client to add a component to the graph.
|
||||
|
||||
@@ -78,6 +78,8 @@ OMX_U32 mmalil_buffer_flags_to_omx(uint32_t flags)
|
||||
omx_flags |= OMX_BUFFERFLAG_CODECSIDEINFO;
|
||||
if (flags & MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT)
|
||||
omx_flags |= OMX_BUFFERFLAG_CAPTURE_PREVIEW;
|
||||
if (flags & MMAL_BUFFER_HEADER_FLAG_CORRUPTED)
|
||||
omx_flags |= OMX_BUFFERFLAG_DATACORRUPT;
|
||||
|
||||
return omx_flags;
|
||||
}
|
||||
@@ -100,6 +102,8 @@ uint32_t mmalil_buffer_flags_to_mmal(OMX_U32 flags)
|
||||
mmal_flags |= MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO;
|
||||
if (flags & OMX_BUFFERFLAG_CAPTURE_PREVIEW)
|
||||
mmal_flags |= MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT;
|
||||
if (flags & OMX_BUFFERFLAG_DATACORRUPT)
|
||||
mmal_flags |= MMAL_BUFFER_HEADER_FLAG_CORRUPTED;
|
||||
|
||||
return mmal_flags;
|
||||
}
|
||||
@@ -169,6 +173,19 @@ static struct {
|
||||
} mmal_omx_audio_coding_table[] =
|
||||
{
|
||||
{MMAL_ENCODING_MP4A, OMX_AUDIO_CodingAAC},
|
||||
{MMAL_ENCODING_MPGA, OMX_AUDIO_CodingMP3},
|
||||
{MMAL_ENCODING_WMA2, OMX_AUDIO_CodingWMA},
|
||||
{MMAL_ENCODING_WMA1, OMX_AUDIO_CodingWMA},
|
||||
{MMAL_ENCODING_AMRNB, OMX_AUDIO_CodingAMR},
|
||||
{MMAL_ENCODING_AMRWB, OMX_AUDIO_CodingAMR},
|
||||
{MMAL_ENCODING_AMRWBP, OMX_AUDIO_CodingAMR},
|
||||
{MMAL_ENCODING_VORBIS, OMX_AUDIO_CodingVORBIS},
|
||||
{MMAL_ENCODING_ALAW, OMX_AUDIO_CodingPCM},
|
||||
{MMAL_ENCODING_MULAW, OMX_AUDIO_CodingPCM},
|
||||
{MMAL_ENCODING_PCM_SIGNED_LE, OMX_AUDIO_CodingPCM},
|
||||
{MMAL_ENCODING_PCM_UNSIGNED_LE,OMX_AUDIO_CodingPCM},
|
||||
{MMAL_ENCODING_PCM_SIGNED_BE, OMX_AUDIO_CodingPCM},
|
||||
{MMAL_ENCODING_PCM_UNSIGNED_BE,OMX_AUDIO_CodingPCM},
|
||||
{MMAL_ENCODING_UNKNOWN, OMX_AUDIO_CodingUnused}
|
||||
};
|
||||
|
||||
@@ -180,7 +197,7 @@ uint32_t mmalil_omx_audio_coding_to_encoding(OMX_AUDIO_CODINGTYPE coding)
|
||||
return mmal_omx_audio_coding_table[i].encoding;
|
||||
}
|
||||
|
||||
OMX_VIDEO_CODINGTYPE mmalil_encoding_to_omx_audio_coding(uint32_t encoding)
|
||||
OMX_AUDIO_CODINGTYPE mmalil_encoding_to_omx_audio_coding(uint32_t encoding)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i = 0; mmal_omx_audio_coding_table[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
|
||||
@@ -188,6 +205,294 @@ OMX_VIDEO_CODINGTYPE mmalil_encoding_to_omx_audio_coding(uint32_t encoding)
|
||||
return mmal_omx_audio_coding_table[i].coding;
|
||||
}
|
||||
|
||||
static struct {
|
||||
OMX_AUDIO_CODINGTYPE coding;
|
||||
OMX_INDEXTYPE index;
|
||||
unsigned int size;
|
||||
} mmal_omx_audio_format_table[] =
|
||||
{
|
||||
{OMX_AUDIO_CodingPCM, OMX_IndexParamAudioPcm, sizeof(OMX_AUDIO_PARAM_PCMMODETYPE)},
|
||||
{OMX_AUDIO_CodingADPCM, OMX_IndexParamAudioAdpcm, sizeof(OMX_AUDIO_PARAM_ADPCMTYPE)},
|
||||
{OMX_AUDIO_CodingAMR, OMX_IndexParamAudioAmr, sizeof(OMX_AUDIO_PARAM_AMRTYPE)},
|
||||
{OMX_AUDIO_CodingGSMFR, OMX_IndexParamAudioGsm_FR, sizeof(OMX_AUDIO_PARAM_GSMFRTYPE)},
|
||||
{OMX_AUDIO_CodingGSMEFR, OMX_IndexParamAudioGsm_EFR, sizeof(OMX_AUDIO_PARAM_GSMEFRTYPE)},
|
||||
{OMX_AUDIO_CodingGSMHR, OMX_IndexParamAudioGsm_HR, sizeof(OMX_AUDIO_PARAM_GSMHRTYPE)},
|
||||
{OMX_AUDIO_CodingPDCFR, OMX_IndexParamAudioPdc_FR, sizeof(OMX_AUDIO_PARAM_PDCFRTYPE)},
|
||||
{OMX_AUDIO_CodingPDCEFR, OMX_IndexParamAudioPdc_EFR, sizeof(OMX_AUDIO_PARAM_PDCEFRTYPE)},
|
||||
{OMX_AUDIO_CodingPDCHR, OMX_IndexParamAudioPdc_HR, sizeof(OMX_AUDIO_PARAM_PDCHRTYPE)},
|
||||
{OMX_AUDIO_CodingTDMAFR, OMX_IndexParamAudioTdma_FR, sizeof(OMX_AUDIO_PARAM_TDMAFRTYPE)},
|
||||
{OMX_AUDIO_CodingTDMAEFR, OMX_IndexParamAudioTdma_EFR, sizeof(OMX_AUDIO_PARAM_TDMAEFRTYPE)},
|
||||
{OMX_AUDIO_CodingQCELP8, OMX_IndexParamAudioQcelp8, sizeof(OMX_AUDIO_PARAM_QCELP8TYPE)},
|
||||
{OMX_AUDIO_CodingQCELP13, OMX_IndexParamAudioQcelp13, sizeof(OMX_AUDIO_PARAM_QCELP13TYPE)},
|
||||
{OMX_AUDIO_CodingEVRC, OMX_IndexParamAudioEvrc, sizeof(OMX_AUDIO_PARAM_EVRCTYPE)},
|
||||
{OMX_AUDIO_CodingSMV, OMX_IndexParamAudioSmv, sizeof(OMX_AUDIO_PARAM_SMVTYPE)},
|
||||
{OMX_AUDIO_CodingG723, OMX_IndexParamAudioG723, sizeof(OMX_AUDIO_PARAM_G723TYPE)},
|
||||
{OMX_AUDIO_CodingG726, OMX_IndexParamAudioG726, sizeof(OMX_AUDIO_PARAM_G726TYPE)},
|
||||
{OMX_AUDIO_CodingG729, OMX_IndexParamAudioG729, sizeof(OMX_AUDIO_PARAM_G729TYPE)},
|
||||
{OMX_AUDIO_CodingAAC, OMX_IndexParamAudioAac, sizeof(OMX_AUDIO_PARAM_AACPROFILETYPE)},
|
||||
{OMX_AUDIO_CodingMP3, OMX_IndexParamAudioMp3, sizeof(OMX_AUDIO_PARAM_MP3TYPE)},
|
||||
{OMX_AUDIO_CodingSBC, OMX_IndexParamAudioSbc, sizeof(OMX_AUDIO_PARAM_SBCTYPE)},
|
||||
{OMX_AUDIO_CodingVORBIS, OMX_IndexParamAudioVorbis, sizeof(OMX_AUDIO_PARAM_VORBISTYPE)},
|
||||
{OMX_AUDIO_CodingWMA, OMX_IndexParamAudioWma, sizeof(OMX_AUDIO_PARAM_WMATYPE)},
|
||||
{OMX_AUDIO_CodingRA, OMX_IndexParamAudioRa, sizeof(OMX_AUDIO_PARAM_RATYPE)},
|
||||
{OMX_AUDIO_CodingMIDI, OMX_IndexParamAudioMidi, sizeof(OMX_AUDIO_PARAM_MIDITYPE)},
|
||||
{OMX_AUDIO_CodingUnused, 0, 0}
|
||||
};
|
||||
|
||||
OMX_INDEXTYPE mmalil_omx_audio_param_index(OMX_AUDIO_CODINGTYPE coding, OMX_U32 *size)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i = 0; mmal_omx_audio_format_table[i].coding != OMX_AUDIO_CodingUnused; i++)
|
||||
if(mmal_omx_audio_format_table[i].coding == coding) break;
|
||||
|
||||
if(size) *size = mmal_omx_audio_format_table[i].size;
|
||||
return mmal_omx_audio_format_table[i].index;
|
||||
}
|
||||
|
||||
MMAL_FOURCC_T mmalil_omx_audio_param_to_format(MMAL_ES_FORMAT_T *format,
|
||||
OMX_AUDIO_CODINGTYPE coding, OMX_FORMAT_PARAM_TYPE *param)
|
||||
{
|
||||
MMAL_AUDIO_FORMAT_T *audio = &format->es->audio;
|
||||
format->encoding = MMAL_ENCODING_UNKNOWN;
|
||||
|
||||
switch(coding)
|
||||
{
|
||||
case OMX_AUDIO_CodingPCM:
|
||||
audio->channels = param->pcm.nChannels;
|
||||
audio->sample_rate = param->pcm.nSamplingRate;
|
||||
audio->bits_per_sample = param->pcm.nBitPerSample;
|
||||
if(param->pcm.ePCMMode == OMX_AUDIO_PCMModeLinear && param->pcm.bInterleaved)
|
||||
{
|
||||
if(param->pcm.eEndian == OMX_EndianBig &&
|
||||
param->pcm.eNumData == OMX_NumericalDataSigned)
|
||||
format->encoding = MMAL_ENCODING_PCM_SIGNED_BE;
|
||||
else if(param->pcm.eEndian == OMX_EndianLittle &&
|
||||
param->pcm.eNumData == OMX_NumericalDataSigned)
|
||||
format->encoding = MMAL_ENCODING_PCM_SIGNED_LE;
|
||||
if(param->pcm.eEndian == OMX_EndianBig &&
|
||||
param->pcm.eNumData == OMX_NumericalDataUnsigned)
|
||||
format->encoding = MMAL_ENCODING_PCM_UNSIGNED_BE;
|
||||
if(param->pcm.eEndian == OMX_EndianLittle &&
|
||||
param->pcm.eNumData == OMX_NumericalDataUnsigned)
|
||||
format->encoding = MMAL_ENCODING_PCM_UNSIGNED_LE;
|
||||
}
|
||||
else if(param->pcm.ePCMMode == OMX_AUDIO_PCMModeALaw)
|
||||
format->encoding = MMAL_ENCODING_ALAW;
|
||||
else if(param->pcm.ePCMMode == OMX_AUDIO_PCMModeMULaw)
|
||||
format->encoding = MMAL_ENCODING_MULAW;
|
||||
break;
|
||||
case OMX_AUDIO_CodingAAC:
|
||||
audio->channels = param->aac.nChannels;
|
||||
audio->sample_rate = param->aac.nSampleRate;
|
||||
format->bitrate = param->aac.nBitRate;
|
||||
switch(param->aac.eAACStreamFormat)
|
||||
{
|
||||
case OMX_AUDIO_AACStreamFormatMP2ADTS:
|
||||
case OMX_AUDIO_AACStreamFormatMP4ADTS:
|
||||
format->encoding = MMAL_ENCODING_MP4A;
|
||||
format->encoding_variant = MMAL_ENCODING_VARIANT_MP4A_ADTS;
|
||||
break;
|
||||
case OMX_AUDIO_AACStreamFormatMP4FF:
|
||||
case OMX_AUDIO_AACStreamFormatRAW:
|
||||
format->encoding = MMAL_ENCODING_MP4A;
|
||||
format->encoding_variant = MMAL_ENCODING_VARIANT_MP4A_DEFAULT;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
case OMX_AUDIO_CodingMP3:
|
||||
format->encoding = MMAL_ENCODING_MPGA;
|
||||
audio->channels = param->mp3.nChannels;
|
||||
audio->sample_rate = param->mp3.nSampleRate;
|
||||
format->bitrate = param->mp3.nBitRate;
|
||||
break;
|
||||
case OMX_AUDIO_CodingWMA:
|
||||
audio->channels = param->wma.nChannels;
|
||||
audio->sample_rate = param->wma.nSamplingRate;
|
||||
audio->block_align = param->wma.nBlockAlign;
|
||||
format->bitrate = param->wma.nBitRate;
|
||||
switch(param->wma.eFormat)
|
||||
{
|
||||
case OMX_AUDIO_WMAFormat7:
|
||||
format->encoding = MMAL_ENCODING_WMA1;
|
||||
break;
|
||||
case OMX_AUDIO_WMAFormat8:
|
||||
case OMX_AUDIO_WMAFormat9:
|
||||
format->encoding = MMAL_ENCODING_WMA2;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
case OMX_AUDIO_CodingVORBIS:
|
||||
format->encoding = MMAL_ENCODING_VORBIS;
|
||||
audio->channels = param->vorbis.nChannels;
|
||||
audio->sample_rate = param->vorbis.nSampleRate;
|
||||
format->bitrate = param->vorbis.nBitRate;
|
||||
break;
|
||||
case OMX_AUDIO_CodingAMR:
|
||||
audio->channels = param->amr.nChannels;
|
||||
audio->sample_rate = 8000;
|
||||
format->bitrate = param->amr.nBitRate;
|
||||
if(param->amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeNB0 &&
|
||||
param->amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeNB7)
|
||||
format->encoding = MMAL_ENCODING_AMRNB;
|
||||
if(param->amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeWB0 &&
|
||||
param->amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeWB8)
|
||||
format->encoding = MMAL_ENCODING_AMRWB;
|
||||
break;
|
||||
case OMX_AUDIO_CodingADPCM:
|
||||
case OMX_AUDIO_CodingGSMFR:
|
||||
case OMX_AUDIO_CodingGSMEFR:
|
||||
case OMX_AUDIO_CodingGSMHR:
|
||||
case OMX_AUDIO_CodingPDCFR:
|
||||
case OMX_AUDIO_CodingPDCEFR:
|
||||
case OMX_AUDIO_CodingPDCHR:
|
||||
case OMX_AUDIO_CodingTDMAFR:
|
||||
case OMX_AUDIO_CodingTDMAEFR:
|
||||
case OMX_AUDIO_CodingQCELP8:
|
||||
case OMX_AUDIO_CodingQCELP13:
|
||||
case OMX_AUDIO_CodingEVRC:
|
||||
case OMX_AUDIO_CodingSMV:
|
||||
case OMX_AUDIO_CodingG711:
|
||||
case OMX_AUDIO_CodingG723:
|
||||
case OMX_AUDIO_CodingG726:
|
||||
case OMX_AUDIO_CodingG729:
|
||||
case OMX_AUDIO_CodingSBC:
|
||||
case OMX_AUDIO_CodingRA:
|
||||
case OMX_AUDIO_CodingMIDI:
|
||||
default:
|
||||
vcos_assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
return format->encoding;
|
||||
}
|
||||
|
||||
OMX_AUDIO_CODINGTYPE mmalil_format_to_omx_audio_param(OMX_FORMAT_PARAM_TYPE *param,
|
||||
OMX_INDEXTYPE *param_index, MMAL_ES_FORMAT_T *format)
|
||||
{
|
||||
MMAL_AUDIO_FORMAT_T *audio = &format->es->audio;
|
||||
OMX_AUDIO_CODINGTYPE coding = mmalil_encoding_to_omx_audio_coding(format->encoding);
|
||||
OMX_U32 size = 0;
|
||||
OMX_INDEXTYPE index = mmalil_omx_audio_param_index(coding, &size);
|
||||
|
||||
if(param_index) *param_index = index;
|
||||
memset(param, 0, size);
|
||||
param->common.nSize = size;
|
||||
|
||||
switch(coding)
|
||||
{
|
||||
case OMX_AUDIO_CodingPCM:
|
||||
param->pcm.nChannels = audio->channels;
|
||||
param->pcm.nSamplingRate = audio->sample_rate;
|
||||
param->pcm.nBitPerSample = audio->bits_per_sample;
|
||||
if(audio->channels == 1)
|
||||
{
|
||||
param->pcm.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
|
||||
}
|
||||
else if(audio->channels == 2)
|
||||
{
|
||||
param->pcm.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
|
||||
param->pcm.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
|
||||
}
|
||||
if(format->encoding == MMAL_ENCODING_PCM_SIGNED_BE ||
|
||||
format->encoding == MMAL_ENCODING_PCM_SIGNED_LE ||
|
||||
format->encoding == MMAL_ENCODING_PCM_UNSIGNED_BE ||
|
||||
format->encoding == MMAL_ENCODING_PCM_UNSIGNED_LE)
|
||||
{
|
||||
param->pcm.ePCMMode = OMX_AUDIO_PCMModeLinear;
|
||||
param->pcm.bInterleaved = OMX_TRUE;
|
||||
param->pcm.eEndian = OMX_EndianLittle;
|
||||
param->pcm.eNumData = OMX_NumericalDataSigned;
|
||||
if(format->encoding == MMAL_ENCODING_PCM_SIGNED_BE ||
|
||||
format->encoding == MMAL_ENCODING_PCM_UNSIGNED_BE)
|
||||
param->pcm.eEndian = OMX_EndianBig;
|
||||
if(format->encoding == MMAL_ENCODING_PCM_UNSIGNED_LE ||
|
||||
format->encoding == MMAL_ENCODING_PCM_UNSIGNED_BE)
|
||||
param->pcm.eNumData = OMX_NumericalDataUnsigned;
|
||||
}
|
||||
else if(format->encoding == MMAL_ENCODING_ALAW)
|
||||
param->pcm.ePCMMode = OMX_AUDIO_PCMModeALaw;
|
||||
else if(format->encoding == MMAL_ENCODING_MULAW)
|
||||
param->pcm.ePCMMode = OMX_AUDIO_PCMModeMULaw;
|
||||
break;
|
||||
case OMX_AUDIO_CodingAAC:
|
||||
param->aac.nChannels = audio->channels;
|
||||
param->aac.nSampleRate = audio->sample_rate;
|
||||
param->aac.nBitRate = format->bitrate;
|
||||
switch(format->encoding_variant)
|
||||
{
|
||||
case MMAL_ENCODING_VARIANT_MP4A_ADTS:
|
||||
param->aac.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
|
||||
break;
|
||||
case MMAL_ENCODING_VARIANT_MP4A_DEFAULT:
|
||||
param->aac.eAACStreamFormat = OMX_AUDIO_AACStreamFormatRAW;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
case OMX_AUDIO_CodingMP3:
|
||||
param->mp3.nChannels = audio->channels;
|
||||
param->mp3.nSampleRate = audio->sample_rate;
|
||||
param->mp3.nBitRate = format->bitrate;
|
||||
break;
|
||||
case OMX_AUDIO_CodingWMA:
|
||||
param->wma.nChannels = audio->channels;
|
||||
param->wma.nSamplingRate = audio->sample_rate;
|
||||
param->wma.nBlockAlign = audio->block_align;
|
||||
param->wma.nBitRate = format->bitrate;
|
||||
switch(format->encoding)
|
||||
{
|
||||
case MMAL_ENCODING_WMA1:
|
||||
param->wma.eFormat = OMX_AUDIO_WMAFormat7;
|
||||
break;
|
||||
case MMAL_ENCODING_WMA2:
|
||||
param->wma.eFormat = OMX_AUDIO_WMAFormat8;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
case OMX_AUDIO_CodingVORBIS:
|
||||
param->vorbis.nChannels = audio->channels;
|
||||
param->vorbis.nSampleRate = audio->sample_rate;
|
||||
param->vorbis.nBitRate = format->bitrate;
|
||||
break;
|
||||
case OMX_AUDIO_CodingAMR:
|
||||
param->amr.nChannels = audio->channels;
|
||||
param->amr.nBitRate = format->bitrate;
|
||||
if(format->encoding == MMAL_ENCODING_AMRNB)
|
||||
param->amr.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0;
|
||||
if(format->encoding == MMAL_ENCODING_AMRWB)
|
||||
param->amr.eAMRBandMode = OMX_AUDIO_AMRBandModeWB0;
|
||||
break;
|
||||
case OMX_AUDIO_CodingADPCM:
|
||||
case OMX_AUDIO_CodingGSMFR:
|
||||
case OMX_AUDIO_CodingGSMEFR:
|
||||
case OMX_AUDIO_CodingGSMHR:
|
||||
case OMX_AUDIO_CodingPDCFR:
|
||||
case OMX_AUDIO_CodingPDCEFR:
|
||||
case OMX_AUDIO_CodingPDCHR:
|
||||
case OMX_AUDIO_CodingTDMAFR:
|
||||
case OMX_AUDIO_CodingTDMAEFR:
|
||||
case OMX_AUDIO_CodingQCELP8:
|
||||
case OMX_AUDIO_CodingQCELP13:
|
||||
case OMX_AUDIO_CodingEVRC:
|
||||
case OMX_AUDIO_CodingSMV:
|
||||
case OMX_AUDIO_CodingG711:
|
||||
case OMX_AUDIO_CodingG723:
|
||||
case OMX_AUDIO_CodingG726:
|
||||
case OMX_AUDIO_CodingG729:
|
||||
case OMX_AUDIO_CodingSBC:
|
||||
case OMX_AUDIO_CodingRA:
|
||||
case OMX_AUDIO_CodingMIDI:
|
||||
default:
|
||||
vcos_assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
return coding;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static struct {
|
||||
uint32_t encoding;
|
||||
@@ -278,10 +583,18 @@ static struct {
|
||||
{
|
||||
{MMAL_ENCODING_I420, OMX_COLOR_FormatYUV420PackedPlanar},
|
||||
{MMAL_ENCODING_I422, OMX_COLOR_FormatYUV422PackedPlanar},
|
||||
{MMAL_ENCODING_I420_SLICE, OMX_COLOR_FormatYUV420PackedPlanar},
|
||||
{MMAL_ENCODING_I422_SLICE, OMX_COLOR_FormatYUV422PackedPlanar},
|
||||
{MMAL_ENCODING_I420, OMX_COLOR_FormatYUV420Planar},
|
||||
{MMAL_ENCODING_NV21, OMX_COLOR_FormatYUV420PackedSemiPlanar},
|
||||
{MMAL_ENCODING_NV21, OMX_COLOR_FormatYUV420SemiPlanar},
|
||||
{MMAL_ENCODING_YV12, OMX_COLOR_FormatYVU420PackedPlanar},
|
||||
{MMAL_ENCODING_NV12, OMX_COLOR_FormatYUV420PackedSemiPlanar},
|
||||
{MMAL_ENCODING_NV12, OMX_COLOR_FormatYUV420SemiPlanar},
|
||||
{MMAL_ENCODING_NV21, OMX_COLOR_FormatYVU420PackedSemiPlanar},
|
||||
{MMAL_ENCODING_YUVUV128, OMX_COLOR_FormatYUVUV128},
|
||||
{MMAL_ENCODING_YUYV, OMX_COLOR_FormatYCbYCr},
|
||||
{MMAL_ENCODING_YVYU, OMX_COLOR_FormatYCrYCb},
|
||||
{MMAL_ENCODING_UYVY, OMX_COLOR_FormatCbYCrY},
|
||||
{MMAL_ENCODING_VYUY, OMX_COLOR_FormatCrYCbY},
|
||||
{MMAL_ENCODING_RGB16, OMX_COLOR_Format16bitRGB565},
|
||||
{MMAL_ENCODING_BGR24, OMX_COLOR_Format24bitRGB888},
|
||||
{MMAL_ENCODING_BGRA, OMX_COLOR_Format32bitARGB8888},
|
||||
@@ -290,6 +603,7 @@ static struct {
|
||||
{MMAL_ENCODING_ARGB, OMX_COLOR_Format32bitBGRA8888},
|
||||
{MMAL_ENCODING_RGBA, OMX_COLOR_Format32bitABGR8888},
|
||||
{MMAL_ENCODING_EGL_IMAGE, OMX_COLOR_FormatBRCMEGL},
|
||||
{MMAL_ENCODING_OPAQUE, OMX_COLOR_FormatBRCMOpaque},
|
||||
{MMAL_ENCODING_UNKNOWN, OMX_COLOR_FormatUnused}
|
||||
};
|
||||
|
||||
@@ -309,6 +623,39 @@ OMX_COLOR_FORMATTYPE mmalil_encoding_to_omx_color_format(uint32_t encoding)
|
||||
return mmal_omx_colorformat_coding_table[i].coding;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static struct {
|
||||
uint32_t mmal;
|
||||
OMX_COLORSPACETYPE omx;
|
||||
} mmal_omx_colorspace_coding_table[] =
|
||||
{
|
||||
{MMAL_COLOR_SPACE_ITUR_BT601, OMX_COLORSPACE_ITU_R_BT601},
|
||||
{MMAL_COLOR_SPACE_ITUR_BT709, OMX_COLORSPACE_ITU_R_BT709},
|
||||
{MMAL_COLOR_SPACE_JPEG_JFIF, OMX_COLORSPACE_JPEG_JFIF},
|
||||
{MMAL_COLOR_SPACE_FCC, OMX_COLORSPACE_FCC},
|
||||
{MMAL_COLOR_SPACE_SMPTE240M, OMX_COLORSPACE_SMPTE240M},
|
||||
{MMAL_COLOR_SPACE_BT470_2_M, OMX_COLORSPACE_BT470_2_M},
|
||||
{MMAL_COLOR_SPACE_BT470_2_BG, OMX_COLORSPACE_BT470_2_BG},
|
||||
{MMAL_COLOR_SPACE_JFIF_Y16_255, OMX_COLORSPACE_JFIF_Y16_255},
|
||||
{MMAL_COLOR_SPACE_UNKNOWN, OMX_COLORSPACE_UNKNOWN}
|
||||
};
|
||||
|
||||
uint32_t mmalil_omx_color_space_to_mmal(OMX_COLORSPACETYPE coding)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i = 0; mmal_omx_colorspace_coding_table[i].mmal != MMAL_COLOR_SPACE_UNKNOWN; i++)
|
||||
if(mmal_omx_colorspace_coding_table[i].omx == coding) break;
|
||||
return mmal_omx_colorspace_coding_table[i].mmal;
|
||||
}
|
||||
|
||||
OMX_COLORSPACETYPE mmalil_color_space_to_omx(uint32_t coding)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i = 0; mmal_omx_colorspace_coding_table[i].mmal != MMAL_COLOR_SPACE_UNKNOWN; i++)
|
||||
if(mmal_omx_colorspace_coding_table[i].mmal == coding) break;
|
||||
return mmal_omx_colorspace_coding_table[i].omx;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static struct {
|
||||
uint32_t mmal;
|
||||
@@ -348,6 +695,7 @@ static struct {
|
||||
{ MMAL_VIDEO_PROFILE_H264_HIGH10, OMX_VIDEO_AVCProfileHigh10, OMX_VIDEO_CodingAVC},
|
||||
{ MMAL_VIDEO_PROFILE_H264_HIGH422, OMX_VIDEO_AVCProfileHigh422, OMX_VIDEO_CodingAVC},
|
||||
{ MMAL_VIDEO_PROFILE_H264_HIGH444, OMX_VIDEO_AVCProfileHigh444, OMX_VIDEO_CodingAVC},
|
||||
{ MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE, OMX_VIDEO_AVCProfileConstrainedBaseline, OMX_VIDEO_CodingAVC},
|
||||
{ MMAL_VIDEO_PROFILE_DUMMY, OMX_VIDEO_AVCProfileMax, OMX_VIDEO_CodingAVC},
|
||||
};
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ extern "C" {
|
||||
#include "interface/vmcs_host/khronos/IL/OMX_Component.h"
|
||||
#include "interface/vmcs_host/khronos/IL/OMX_Video.h"
|
||||
#include "interface/vmcs_host/khronos/IL/OMX_Audio.h"
|
||||
#include "interface/vmcs_host/khronos/IL/OMX_Broadcom.h"
|
||||
|
||||
/** Convert MMAL status codes into OMX error codes.
|
||||
*
|
||||
@@ -90,7 +91,7 @@ void mmalil_buffer_header_to_mmal(MMAL_BUFFER_HEADER_T *mmal, OMX_BUFFERHEADERTY
|
||||
OMX_PORTDOMAINTYPE mmalil_es_type_to_omx_domain(MMAL_ES_TYPE_T type);
|
||||
MMAL_ES_TYPE_T mmalil_omx_domain_to_es_type(OMX_PORTDOMAINTYPE domain);
|
||||
uint32_t mmalil_omx_audio_coding_to_encoding(OMX_AUDIO_CODINGTYPE coding);
|
||||
OMX_VIDEO_CODINGTYPE mmalil_encoding_to_omx_audio_coding(uint32_t encoding);
|
||||
OMX_AUDIO_CODINGTYPE mmalil_encoding_to_omx_audio_coding(uint32_t encoding);
|
||||
uint32_t mmalil_omx_video_coding_to_encoding(OMX_VIDEO_CODINGTYPE coding);
|
||||
OMX_VIDEO_CODINGTYPE mmalil_encoding_to_omx_video_coding(uint32_t encoding);
|
||||
uint32_t mmalil_omx_image_coding_to_encoding(OMX_IMAGE_CODINGTYPE coding);
|
||||
@@ -98,6 +99,8 @@ OMX_IMAGE_CODINGTYPE mmalil_encoding_to_omx_image_coding(uint32_t encoding);
|
||||
uint32_t mmalil_omx_coding_to_encoding(uint32_t encoding, OMX_PORTDOMAINTYPE domain);
|
||||
uint32_t mmalil_omx_color_format_to_encoding(OMX_COLOR_FORMATTYPE coding);
|
||||
OMX_COLOR_FORMATTYPE mmalil_encoding_to_omx_color_format(uint32_t encoding);
|
||||
uint32_t mmalil_omx_color_space_to_mmal(OMX_COLORSPACETYPE coding);
|
||||
OMX_COLORSPACETYPE mmalil_color_space_to_omx(uint32_t coding);
|
||||
uint32_t mmalil_omx_video_profile_to_mmal(OMX_U32 level, OMX_VIDEO_CODINGTYPE coding);
|
||||
OMX_U32 mmalil_video_profile_to_omx(uint32_t profile);
|
||||
uint32_t mmalil_omx_video_level_to_mmal(OMX_U32 level, OMX_VIDEO_CODINGTYPE coding);
|
||||
@@ -105,6 +108,78 @@ OMX_U32 mmalil_video_level_to_omx(uint32_t level);
|
||||
MMAL_VIDEO_RATECONTROL_T mmalil_omx_video_ratecontrol_to_mmal(OMX_VIDEO_CONTROLRATETYPE omx);
|
||||
OMX_VIDEO_CONTROLRATETYPE mmalil_video_ratecontrol_to_omx(MMAL_VIDEO_RATECONTROL_T mmal);
|
||||
|
||||
/** Union of all the OMX_VIDEO/AUDIO_PARAM types */
|
||||
typedef union OMX_FORMAT_PARAM_TYPE {
|
||||
OMX_PARAM_U32TYPE common;
|
||||
|
||||
/* Video */
|
||||
OMX_VIDEO_PARAM_AVCTYPE avc;
|
||||
OMX_VIDEO_PARAM_H263TYPE h263;
|
||||
OMX_VIDEO_PARAM_MPEG2TYPE mpeg2;
|
||||
OMX_VIDEO_PARAM_MPEG4TYPE mpeg4;
|
||||
OMX_VIDEO_PARAM_WMVTYPE wmv;
|
||||
OMX_VIDEO_PARAM_RVTYPE rv;
|
||||
|
||||
/* Audio */
|
||||
OMX_AUDIO_PARAM_PCMMODETYPE pcm;
|
||||
OMX_AUDIO_PARAM_MP3TYPE mp3;
|
||||
OMX_AUDIO_PARAM_AACPROFILETYPE aac;
|
||||
OMX_AUDIO_PARAM_VORBISTYPE vorbis;
|
||||
OMX_AUDIO_PARAM_WMATYPE wma;
|
||||
OMX_AUDIO_PARAM_RATYPE ra;
|
||||
OMX_AUDIO_PARAM_SBCTYPE sbc;
|
||||
OMX_AUDIO_PARAM_ADPCMTYPE adpcm;
|
||||
OMX_AUDIO_PARAM_G723TYPE g723;
|
||||
OMX_AUDIO_PARAM_G726TYPE g726;
|
||||
OMX_AUDIO_PARAM_G729TYPE g729;
|
||||
OMX_AUDIO_PARAM_AMRTYPE amr;
|
||||
OMX_AUDIO_PARAM_GSMFRTYPE gsmfr;
|
||||
OMX_AUDIO_PARAM_GSMHRTYPE gsmhr;
|
||||
OMX_AUDIO_PARAM_GSMEFRTYPE gsmefr;
|
||||
OMX_AUDIO_PARAM_TDMAFRTYPE tdmafr;
|
||||
OMX_AUDIO_PARAM_TDMAEFRTYPE tdmaefr;
|
||||
OMX_AUDIO_PARAM_PDCFRTYPE pdcfr;
|
||||
OMX_AUDIO_PARAM_PDCEFRTYPE pdcefr;
|
||||
OMX_AUDIO_PARAM_PDCHRTYPE pdchr;
|
||||
OMX_AUDIO_PARAM_QCELP8TYPE qcelp8;
|
||||
OMX_AUDIO_PARAM_QCELP13TYPE qcelp13;
|
||||
OMX_AUDIO_PARAM_EVRCTYPE evrc;
|
||||
OMX_AUDIO_PARAM_SMVTYPE smv;
|
||||
OMX_AUDIO_PARAM_MIDITYPE midi;
|
||||
|
||||
} OMX_FORMAT_PARAM_TYPE;
|
||||
|
||||
/** Get the OMX_IndexParamAudio index corresponding to a specified audio coding type.
|
||||
*
|
||||
* @param coding Audio coding type.
|
||||
* @param size Pointer used to return the size of the parameter.
|
||||
*
|
||||
* @return OMX index or 0 if no match was found.
|
||||
*/
|
||||
OMX_INDEXTYPE mmalil_omx_audio_param_index(OMX_AUDIO_CODINGTYPE coding, OMX_U32 *size);
|
||||
|
||||
/** Convert an OMX_IndexParamAudio into a MMAL elementary stream format.
|
||||
*
|
||||
* @param format Format structure to update.
|
||||
* @param coding Audio coding type.
|
||||
* @param param Source OMX_IndexParamAudio structure.
|
||||
*
|
||||
* @return The MMAL encoding if a match was found or MMAL_ENCODING_UNKNOWN otherwise.
|
||||
*/
|
||||
MMAL_FOURCC_T mmalil_omx_audio_param_to_format(MMAL_ES_FORMAT_T *format,
|
||||
OMX_AUDIO_CODINGTYPE coding, OMX_FORMAT_PARAM_TYPE *param);
|
||||
|
||||
/** Convert a MMAL elementary stream format into a OMX_IndexParamAudio structure.
|
||||
*
|
||||
* @param param OMX_IndexParamAudio structure to update.
|
||||
* @param param_index returns the OMX_IndexParamAudio index corresponding to the format.
|
||||
* @param format Source format structure.
|
||||
*
|
||||
* @return The OMX aduio coding type if a match was found or OMX_AUDIO_CodingUnused otherwise.
|
||||
*/
|
||||
OMX_AUDIO_CODINGTYPE mmalil_format_to_omx_audio_param(OMX_FORMAT_PARAM_TYPE *param,
|
||||
OMX_INDEXTYPE *param_index, MMAL_ES_FORMAT_T *format);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
218
interface/mmal/util/mmal_list.c
Normal file
218
interface/mmal/util/mmal_list.c
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "interface/vcos/vcos.h"
|
||||
#include "interface/mmal/util/mmal_list.h"
|
||||
|
||||
|
||||
/* Private list context */
|
||||
typedef struct MMAL_LIST_PRIVATE_T
|
||||
{
|
||||
MMAL_LIST_T list; /* must be first */
|
||||
VCOS_MUTEX_T lock;
|
||||
} MMAL_LIST_PRIVATE_T;
|
||||
|
||||
|
||||
/* Lock the list. */
|
||||
static inline void mmal_list_lock(MMAL_LIST_T *list)
|
||||
{
|
||||
vcos_mutex_lock(&((MMAL_LIST_PRIVATE_T*)list)->lock);
|
||||
}
|
||||
|
||||
/* Unlock the list. */
|
||||
static inline void mmal_list_unlock(MMAL_LIST_T *list)
|
||||
{
|
||||
vcos_mutex_unlock(&((MMAL_LIST_PRIVATE_T*)list)->lock);
|
||||
}
|
||||
|
||||
/* Create a new linked list. */
|
||||
MMAL_LIST_T* mmal_list_create(void)
|
||||
{
|
||||
MMAL_LIST_PRIVATE_T *private;
|
||||
|
||||
private = vcos_malloc(sizeof(MMAL_LIST_PRIVATE_T), "mmal-list");
|
||||
if (private == NULL)
|
||||
goto error;
|
||||
|
||||
if (vcos_mutex_create(&private->lock, "mmal-list lock") != VCOS_SUCCESS)
|
||||
goto error;
|
||||
|
||||
private->list.first = NULL;
|
||||
private->list.last = NULL;
|
||||
private->list.length = 0;
|
||||
|
||||
return &private->list;
|
||||
|
||||
error:
|
||||
vcos_free(private);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Destroy a linked list. */
|
||||
void mmal_list_destroy(MMAL_LIST_T *list)
|
||||
{
|
||||
MMAL_LIST_PRIVATE_T *private = (MMAL_LIST_PRIVATE_T*)list;
|
||||
|
||||
vcos_mutex_delete(&private->lock);
|
||||
vcos_free(private);
|
||||
}
|
||||
|
||||
/* Remove the last element in the list. */
|
||||
MMAL_LIST_ELEMENT_T* mmal_list_pop_back(MMAL_LIST_T *list)
|
||||
{
|
||||
MMAL_LIST_ELEMENT_T *element;
|
||||
|
||||
mmal_list_lock(list);
|
||||
|
||||
element = list->last;
|
||||
if (element != NULL)
|
||||
{
|
||||
list->length--;
|
||||
|
||||
list->last = element->prev;
|
||||
if (list->last)
|
||||
list->last->next = NULL;
|
||||
else
|
||||
list->first = NULL; /* list is now empty */
|
||||
|
||||
element->prev = NULL;
|
||||
element->next = NULL;
|
||||
}
|
||||
|
||||
mmal_list_unlock(list);
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
/* Remove the first element in the list. */
|
||||
MMAL_LIST_ELEMENT_T* mmal_list_pop_front(MMAL_LIST_T *list)
|
||||
{
|
||||
MMAL_LIST_ELEMENT_T *element;
|
||||
|
||||
mmal_list_lock(list);
|
||||
|
||||
element = list->first;
|
||||
if (element != NULL)
|
||||
{
|
||||
list->length--;
|
||||
|
||||
list->first = element->next;
|
||||
if (list->first)
|
||||
list->first->prev = NULL;
|
||||
else
|
||||
list->last = NULL; /* list is now empty */
|
||||
|
||||
element->prev = NULL;
|
||||
element->next = NULL;
|
||||
}
|
||||
|
||||
mmal_list_unlock(list);
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
/* Add an element to the front of the list. */
|
||||
void mmal_list_push_front(MMAL_LIST_T *list, MMAL_LIST_ELEMENT_T *element)
|
||||
{
|
||||
mmal_list_lock(list);
|
||||
|
||||
list->length++;
|
||||
|
||||
element->prev = NULL;
|
||||
element->next = list->first;
|
||||
|
||||
if (list->first)
|
||||
list->first->prev = element;
|
||||
else
|
||||
list->last = element; /* list was empty */
|
||||
|
||||
list->first = element;
|
||||
|
||||
mmal_list_unlock(list);
|
||||
}
|
||||
|
||||
/* Add an element to the back of the list. */
|
||||
void mmal_list_push_back(MMAL_LIST_T *list, MMAL_LIST_ELEMENT_T *element)
|
||||
{
|
||||
mmal_list_lock(list);
|
||||
|
||||
list->length++;
|
||||
|
||||
element->next = NULL;
|
||||
element->prev = list->last;
|
||||
|
||||
if (list->last)
|
||||
list->last->next = element;
|
||||
else
|
||||
list->first = element; /* list was empty */
|
||||
|
||||
list->last = element;
|
||||
|
||||
mmal_list_unlock(list);
|
||||
}
|
||||
|
||||
/* Insert an element into the list. */
|
||||
void mmal_list_insert(MMAL_LIST_T *list, MMAL_LIST_ELEMENT_T *element, MMAL_LIST_COMPARE_T compare)
|
||||
{
|
||||
MMAL_LIST_ELEMENT_T *cur;
|
||||
|
||||
mmal_list_lock(list);
|
||||
|
||||
if (list->first == NULL)
|
||||
{
|
||||
/* List empty */
|
||||
mmal_list_unlock(list);
|
||||
mmal_list_push_front(list, element);
|
||||
return;
|
||||
}
|
||||
|
||||
cur = list->first;
|
||||
while (cur)
|
||||
{
|
||||
if (compare(element, cur))
|
||||
{
|
||||
/* Slot found! */
|
||||
list->length++;
|
||||
if (cur == list->first)
|
||||
list->first = element;
|
||||
else
|
||||
cur->prev->next = element;
|
||||
element->prev = cur->prev;
|
||||
element->next = cur;
|
||||
cur->prev = element;
|
||||
mmal_list_unlock(list);
|
||||
return;
|
||||
}
|
||||
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
/* If we get here, none of the existing elements are greater
|
||||
* than the new on, so just add it to the back of the list */
|
||||
mmal_list_unlock(list);
|
||||
mmal_list_push_back(list, element);
|
||||
}
|
||||
@@ -25,30 +25,103 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
typedef struct list_elem {
|
||||
struct list_elem *next;
|
||||
} list_elem;
|
||||
#ifndef MMAL_LIST_H
|
||||
#define MMAL_LIST_H
|
||||
|
||||
static inline void list_insert(list_elem **head, list_elem *item) {
|
||||
item->next = *head;
|
||||
*head = item;
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \defgroup MmalList Generic Linked List
|
||||
* This provides a thread-safe implementation of a linked list which can be used
|
||||
* with any data type. */
|
||||
/* @{ */
|
||||
|
||||
/** Single element in the list */
|
||||
typedef struct MMAL_LIST_ELEMENT_T
|
||||
{
|
||||
struct MMAL_LIST_ELEMENT_T *next;
|
||||
struct MMAL_LIST_ELEMENT_T *prev;
|
||||
} MMAL_LIST_ELEMENT_T;
|
||||
|
||||
/** Linked list type.
|
||||
* Clients shouldn't modify this directly. Use the provided API functions to
|
||||
* add new elements. The public members are only for debug purposes.
|
||||
* */
|
||||
typedef struct MMAL_LIST_T
|
||||
{
|
||||
unsigned int length; /**< Number of elements in the list (read-only) */
|
||||
MMAL_LIST_ELEMENT_T *first; /**< First element in the list (read-only) */
|
||||
MMAL_LIST_ELEMENT_T *last; /**< Last element in the list (read-only) */
|
||||
} MMAL_LIST_T;
|
||||
|
||||
/** Create a new linked list.
|
||||
*
|
||||
* @return Pointer to new queue (NULL on failure).
|
||||
*/
|
||||
MMAL_LIST_T* mmal_list_create(void);
|
||||
|
||||
/** Destroy a linked list.
|
||||
*
|
||||
* @param list List to destroy
|
||||
*/
|
||||
void mmal_list_destroy(MMAL_LIST_T *list);
|
||||
|
||||
/** Remove the last element in the list.
|
||||
*
|
||||
* @param list List to remove from
|
||||
*
|
||||
* @return Pointer to the last element (or NULL if empty)
|
||||
*/
|
||||
MMAL_LIST_ELEMENT_T* mmal_list_pop_back(MMAL_LIST_T *list);
|
||||
|
||||
/** Remove the first element in the list.
|
||||
*
|
||||
* @param list List to remove from
|
||||
*
|
||||
* @return Pointer to the first element (or NULL if empty)
|
||||
*/
|
||||
MMAL_LIST_ELEMENT_T* mmal_list_pop_front(MMAL_LIST_T *list);
|
||||
|
||||
/** Add an element to the front of the list.
|
||||
*
|
||||
* @param list List to add to
|
||||
* @param element The element to add
|
||||
*/
|
||||
void mmal_list_push_front(MMAL_LIST_T *list, MMAL_LIST_ELEMENT_T *element);
|
||||
|
||||
/** Add an element to the back of the list.
|
||||
*
|
||||
* @param list List to add to
|
||||
* @param element The element to add
|
||||
*/
|
||||
void mmal_list_push_back(MMAL_LIST_T *list, MMAL_LIST_ELEMENT_T *element);
|
||||
|
||||
/** List comparison function.
|
||||
* This is supplied by a client when inserting an element in
|
||||
* the middle of the list. The list will always insert a smaller
|
||||
* element in front of a larger element.
|
||||
*
|
||||
* @return TRUE: lhs < rhs
|
||||
* FALSE: lhs >= rhs
|
||||
*/
|
||||
typedef int (*MMAL_LIST_COMPARE_T)(MMAL_LIST_ELEMENT_T *lhs, MMAL_LIST_ELEMENT_T *rhs);
|
||||
|
||||
/** Insert an element into the list.
|
||||
* The location where the element is inserted is determined using
|
||||
* the supplied comparison function. Smaller elements are inserted
|
||||
* in front of larger elements.
|
||||
*
|
||||
* @param list List to add to
|
||||
* @param element The element to insert
|
||||
* @param compare Comparison function supplied by the client
|
||||
*/
|
||||
void mmal_list_insert(MMAL_LIST_T *list, MMAL_LIST_ELEMENT_T *element, MMAL_LIST_COMPARE_T compare);
|
||||
|
||||
/* @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int list_remove(list_elem **plist, list_elem *item) {
|
||||
while (*plist && ((*plist) != item)) {
|
||||
plist = &((*plist)->next);
|
||||
}
|
||||
|
||||
if (*plist) {
|
||||
*plist = item->next;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* MMAL_LIST_H */
|
||||
|
||||
@@ -39,7 +39,7 @@ static MMAL_STATUS_T parse_enum(int *dest, string_pair_t *pairs, size_t n_pairs,
|
||||
size_t i;
|
||||
for (i=0; i<n_pairs; i++)
|
||||
{
|
||||
if (strcasecmp(str, pairs[i].string) == 0)
|
||||
if (vcos_strcasecmp(str, pairs[i].string) == 0)
|
||||
{
|
||||
*dest = pairs[i].value;
|
||||
return MMAL_SUCCESS;
|
||||
@@ -66,7 +66,7 @@ MMAL_STATUS_T mmal_parse_video_size(uint32_t *w, uint32_t *h, const char *str)
|
||||
size_t i;
|
||||
for (i=0; i<vcos_countof(sizes); i++)
|
||||
{
|
||||
if (strcasecmp(str, sizes[i].name) == 0)
|
||||
if (vcos_strcasecmp(str, sizes[i].name) == 0)
|
||||
{
|
||||
*w = sizes[i].width;
|
||||
*h = sizes[i].height;
|
||||
@@ -158,6 +158,7 @@ MMAL_STATUS_T mmal_parse_geometry(MMAL_RECT_T *dest, const char *str)
|
||||
MMAL_STATUS_T ret;
|
||||
uint32_t w, h, x, y;
|
||||
x = y = w = h = 0;
|
||||
/* coverity[secure_coding] */
|
||||
if (sscanf(str, "%d*%d+%d+%d", &w,&h,&x,&y) == 4 ||
|
||||
sscanf(str, "%d*%d", &w,&h) == 2)
|
||||
{
|
||||
|
||||
@@ -34,6 +34,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "interface/mmal/mmal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Parse a video size. e.g. "1080p" gives 1920x1080.
|
||||
*
|
||||
* @param w width result
|
||||
@@ -81,5 +85,8 @@ MMAL_STATUS_T mmal_parse_geometry(MMAL_RECT_T *dest, const char *str);
|
||||
*/
|
||||
MMAL_STATUS_T mmal_parse_video_codec(uint32_t *dest, const char *str);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -71,8 +71,10 @@ static struct {
|
||||
} pixel_pitch[] =
|
||||
{
|
||||
{MMAL_ENCODING_I420, 1, 1},
|
||||
{MMAL_ENCODING_YV12, 1, 1},
|
||||
{MMAL_ENCODING_I422, 1, 1},
|
||||
{MMAL_ENCODING_NV21, 1, 1},
|
||||
{MMAL_ENCODING_NV12, 1, 1},
|
||||
{MMAL_ENCODING_ARGB, 4, 1},
|
||||
{MMAL_ENCODING_RGBA, 4, 1},
|
||||
{MMAL_ENCODING_RGB32, 4, 1},
|
||||
@@ -113,6 +115,22 @@ uint32_t mmal_encoding_width_to_stride(uint32_t encoding, uint32_t width)
|
||||
return pixel_pitch[i].pitch_num * width / pixel_pitch[i].pitch_den;
|
||||
}
|
||||
|
||||
const char* mmal_port_type_to_string(MMAL_PORT_TYPE_T type)
|
||||
{
|
||||
const char *str;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case MMAL_PORT_TYPE_INPUT: str = "in"; break;
|
||||
case MMAL_PORT_TYPE_OUTPUT: str = "out"; break;
|
||||
case MMAL_PORT_TYPE_CLOCK: str = "clk"; break;
|
||||
case MMAL_PORT_TYPE_CONTROL: str = "ctr"; break;
|
||||
default: str = "invalid"; break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
MMAL_PARAMETER_HEADER_T *mmal_port_parameter_alloc_get(MMAL_PORT_T *port,
|
||||
uint32_t id, uint32_t size, MMAL_STATUS_T *p_status)
|
||||
{
|
||||
@@ -289,6 +307,11 @@ MMAL_PORT_T *mmal_util_get_port(MMAL_COMPONENT_T *comp, MMAL_PORT_TYPE_T type, u
|
||||
list = comp->output;
|
||||
break;
|
||||
|
||||
case MMAL_PORT_TYPE_CLOCK:
|
||||
num = comp->clock_num;
|
||||
list = comp->clock;
|
||||
break;
|
||||
|
||||
case MMAL_PORT_TYPE_CONTROL:
|
||||
num = 1;
|
||||
list = &comp->control;
|
||||
@@ -319,7 +342,7 @@ char *mmal_4cc_to_string(char *buf, size_t len, uint32_t fourcc)
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(buf, "<0>");
|
||||
snprintf(buf, len, "<0>");
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -66,6 +66,13 @@ uint32_t mmal_encoding_stride_to_width(uint32_t encoding, uint32_t stride);
|
||||
*/
|
||||
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
|
||||
@@ -149,7 +156,8 @@ MMAL_PORT_T *mmal_util_get_port(MMAL_COMPONENT_T *comp, MMAL_PORT_TYPE_T type, u
|
||||
/** Convert a 4cc into a string.
|
||||
*
|
||||
* @param buf Destination for result
|
||||
* @param magic 4CC
|
||||
* @param len Size of result buffer
|
||||
* @param fourcc 4cc to be converted
|
||||
* @return converted string (buf)
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -38,23 +38,61 @@ MMAL_STATUS_T mmal_port_parameter_set_boolean(MMAL_PORT_T *port, uint32_t id, MM
|
||||
MMAL_STATUS_T mmal_port_parameter_get_boolean(MMAL_PORT_T *port, uint32_t id, MMAL_BOOL_T *value)
|
||||
{
|
||||
MMAL_PARAMETER_BOOLEAN_T param = {{id, sizeof(param)}, 0};
|
||||
// coverity[overrun-buffer-val] Structure accessed correctly via size field
|
||||
MMAL_STATUS_T status = mmal_port_parameter_get(port, ¶m.hdr);
|
||||
if (status == MMAL_SUCCESS)
|
||||
*value = param.enable;
|
||||
return status;
|
||||
}
|
||||
|
||||
/** Helper function to set the value of a 64 bits unsigned integer parameter */
|
||||
MMAL_STATUS_T mmal_port_parameter_set_uint64(MMAL_PORT_T *port, uint32_t id, uint64_t value)
|
||||
{
|
||||
MMAL_PARAMETER_UINT64_T param = {{id, sizeof(param)}, value};
|
||||
return mmal_port_parameter_set(port, ¶m.hdr);
|
||||
}
|
||||
|
||||
/** Helper function to get the value of a 64 bits unsigned integer parameter */
|
||||
MMAL_STATUS_T mmal_port_parameter_get_uint64(MMAL_PORT_T *port, uint32_t id, uint64_t *value)
|
||||
{
|
||||
MMAL_PARAMETER_UINT64_T param = {{id, sizeof(param)}, 0LL};
|
||||
// coverity[overrun-buffer-val] Structure accessed correctly via size field
|
||||
MMAL_STATUS_T status = mmal_port_parameter_get(port, ¶m.hdr);
|
||||
if (status == MMAL_SUCCESS)
|
||||
*value = param.value;
|
||||
return status;
|
||||
}
|
||||
|
||||
/** Helper function to set the value of a 64 bits signed integer parameter */
|
||||
MMAL_STATUS_T mmal_port_parameter_set_int64(MMAL_PORT_T *port, uint32_t id, int64_t value)
|
||||
{
|
||||
MMAL_PARAMETER_INT64_T param = {{id, sizeof(param)}, value};
|
||||
return mmal_port_parameter_set(port, ¶m.hdr);
|
||||
}
|
||||
|
||||
/** Helper function to get the value of a 64 bits signed integer parameter */
|
||||
MMAL_STATUS_T mmal_port_parameter_get_int64(MMAL_PORT_T *port, uint32_t id, int64_t *value)
|
||||
{
|
||||
MMAL_PARAMETER_INT64_T param = {{id, sizeof(param)}, 0LL};
|
||||
// coverity[overrun-buffer-val] Structure accessed correctly via size field
|
||||
MMAL_STATUS_T status = mmal_port_parameter_get(port, ¶m.hdr);
|
||||
if (status == MMAL_SUCCESS)
|
||||
*value = param.value;
|
||||
return status;
|
||||
}
|
||||
|
||||
/** Helper function to set the value of a 32 bits unsigned integer parameter */
|
||||
MMAL_STATUS_T mmal_port_parameter_set_uint32(MMAL_PORT_T *port, uint32_t id, uint32_t value)
|
||||
{
|
||||
MMAL_PARAMETER_INT32_T param = {{id, sizeof(param)}, value};
|
||||
MMAL_PARAMETER_UINT32_T param = {{id, sizeof(param)}, value};
|
||||
return mmal_port_parameter_set(port, ¶m.hdr);
|
||||
}
|
||||
|
||||
/** Helper function to get the value of a 32 bits unsigned integer parameter */
|
||||
MMAL_STATUS_T mmal_port_parameter_get_uint32(MMAL_PORT_T *port, uint32_t id, uint32_t *value)
|
||||
{
|
||||
MMAL_PARAMETER_INT32_T param = {{id, sizeof(param)}, 0};
|
||||
MMAL_PARAMETER_UINT32_T param = {{id, sizeof(param)}, 0};
|
||||
// coverity[overrun-buffer-val] Structure accessed correctly via size field
|
||||
MMAL_STATUS_T status = mmal_port_parameter_get(port, ¶m.hdr);
|
||||
if (status == MMAL_SUCCESS)
|
||||
*value = param.value;
|
||||
@@ -64,14 +102,15 @@ MMAL_STATUS_T mmal_port_parameter_get_uint32(MMAL_PORT_T *port, uint32_t id, uin
|
||||
/** Helper function to set the value of a 32 bits signed integer parameter */
|
||||
MMAL_STATUS_T mmal_port_parameter_set_int32(MMAL_PORT_T *port, uint32_t id, int32_t value)
|
||||
{
|
||||
MMAL_PARAMETER_UINT32_T param = {{id, sizeof(param)}, value};
|
||||
MMAL_PARAMETER_INT32_T param = {{id, sizeof(param)}, value};
|
||||
return mmal_port_parameter_set(port, ¶m.hdr);
|
||||
}
|
||||
|
||||
/** Helper function to get the value of a 32 bits signed integer parameter */
|
||||
MMAL_STATUS_T mmal_port_parameter_get_int32(MMAL_PORT_T *port, uint32_t id, int32_t *value)
|
||||
{
|
||||
MMAL_PARAMETER_UINT32_T param = {{id, sizeof(param)}, 0};
|
||||
MMAL_PARAMETER_INT32_T param = {{id, sizeof(param)}, 0};
|
||||
// coverity[overrun-buffer-val] Structure accessed correctly via size field
|
||||
MMAL_STATUS_T status = mmal_port_parameter_get(port, ¶m.hdr);
|
||||
if (status == MMAL_SUCCESS)
|
||||
*value = param.value;
|
||||
@@ -89,26 +128,53 @@ MMAL_STATUS_T mmal_port_parameter_set_rational(MMAL_PORT_T *port, uint32_t id, M
|
||||
MMAL_STATUS_T mmal_port_parameter_get_rational(MMAL_PORT_T *port, uint32_t id, MMAL_RATIONAL_T *value)
|
||||
{
|
||||
MMAL_PARAMETER_RATIONAL_T param = {{id, sizeof(param)}, {0,0}};
|
||||
// coverity[overrun-buffer-val] Structure accessed correctly via size field
|
||||
MMAL_STATUS_T status = mmal_port_parameter_get(port, ¶m.hdr);
|
||||
if (status == MMAL_SUCCESS)
|
||||
*value = param.value;
|
||||
return status;
|
||||
}
|
||||
|
||||
/** Helper function to set a MMAL_PARAMETER_URI_T parameter on a port */
|
||||
MMAL_STATUS_T mmal_util_port_set_uri(MMAL_PORT_T *port, const char *uri)
|
||||
/** Helper function to set the value of a string parameter */
|
||||
MMAL_STATUS_T mmal_port_parameter_set_string(MMAL_PORT_T *port, uint32_t id, const char *value)
|
||||
{
|
||||
MMAL_PARAMETER_URI_T *param = 0;
|
||||
MMAL_PARAMETER_STRING_T *param = 0;
|
||||
MMAL_STATUS_T status;
|
||||
size_t param_size = sizeof(MMAL_PARAMETER_URI_T) + strlen(uri) + 1;
|
||||
size_t param_size = sizeof(param->hdr) + strlen(value) + 1;
|
||||
|
||||
param = calloc(1, param_size);
|
||||
if (!param)
|
||||
return MMAL_ENOMEM;
|
||||
|
||||
param->hdr.id = MMAL_PARAMETER_URI;
|
||||
param->hdr.id = id;
|
||||
param->hdr.size = param_size;
|
||||
strcpy(param->uri, uri);
|
||||
memcpy(param->str, value, strlen(value)+1);
|
||||
status = mmal_port_parameter_set(port, ¶m->hdr);
|
||||
free(param);
|
||||
return status;
|
||||
}
|
||||
|
||||
/** Helper function to set a MMAL_PARAMETER_URI_T parameter on a port */
|
||||
MMAL_STATUS_T mmal_util_port_set_uri(MMAL_PORT_T *port, const char *uri)
|
||||
{
|
||||
return mmal_port_parameter_set_string(port, MMAL_PARAMETER_URI, uri);
|
||||
}
|
||||
|
||||
/** Helper function to set the value of an array of bytes parameter */
|
||||
MMAL_STATUS_T mmal_port_parameter_set_bytes(MMAL_PORT_T *port, uint32_t id,
|
||||
const uint8_t *data, unsigned int size)
|
||||
{
|
||||
MMAL_PARAMETER_BYTES_T *param = 0;
|
||||
MMAL_STATUS_T status;
|
||||
size_t param_size = sizeof(param->hdr) + size;
|
||||
|
||||
param = calloc(1, param_size);
|
||||
if (!param)
|
||||
return MMAL_ENOMEM;
|
||||
|
||||
param->hdr.id = id;
|
||||
param->hdr.size = param_size;
|
||||
memcpy(param->data, data, size);
|
||||
status = mmal_port_parameter_set(port, ¶m->hdr);
|
||||
free(param);
|
||||
return status;
|
||||
@@ -143,10 +209,13 @@ MMAL_STATUS_T mmal_util_get_core_port_stats(MMAL_PORT_T *port,
|
||||
{
|
||||
MMAL_PARAMETER_CORE_STATISTICS_T param;
|
||||
MMAL_STATUS_T ret;
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
param.hdr.id = MMAL_PARAMETER_CORE_STATISTICS;
|
||||
param.hdr.size = sizeof(param);
|
||||
param.dir = dir;
|
||||
param.reset = reset;
|
||||
// coverity[overrun-buffer-val] Structure accessed correctly via size field
|
||||
ret = mmal_port_parameter_get(port, ¶m.hdr);
|
||||
if (ret == MMAL_SUCCESS)
|
||||
*stats = param.stats;
|
||||
|
||||
@@ -25,14 +25,18 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef MMAL_UTIL_PARAMS_H
|
||||
#define MMAL_UTIL_PARAMS_H
|
||||
|
||||
#include "interface/mmal/mmal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file Utility functions to set some common parameters.
|
||||
* @file
|
||||
* Utility functions to set some common parameters.
|
||||
*/
|
||||
|
||||
/** Helper function to set the value of a boolean parameter.
|
||||
@@ -53,6 +57,42 @@ MMAL_STATUS_T mmal_port_parameter_set_boolean(MMAL_PORT_T *port, uint32_t id, MM
|
||||
*/
|
||||
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
|
||||
@@ -107,6 +147,26 @@ MMAL_STATUS_T mmal_port_parameter_set_rational(MMAL_PORT_T *port, uint32_t id, M
|
||||
*/
|
||||
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
|
||||
@@ -135,10 +195,16 @@ MMAL_STATUS_T mmal_util_camera_use_stc_timestamp(MMAL_PORT_T *port, MMAL_CAMERA_
|
||||
/** 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
|
||||
|
||||
150
interface/mmal/util/mmal_util_rational.c
Normal file
150
interface/mmal/util/mmal_util_rational.c
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include "interface/mmal/util/mmal_util_rational.h"
|
||||
|
||||
#define Q16_ONE (1 << 16)
|
||||
|
||||
#define ABS(v) (((v) < 0) ? -(v) : (v))
|
||||
|
||||
/** Calculate the greatest common denominator between 2 integers.
|
||||
* Avoids division. */
|
||||
static int32_t gcd(int32_t a, int32_t b)
|
||||
{
|
||||
int shift;
|
||||
|
||||
if (a == 0 || b == 0)
|
||||
return 1;
|
||||
|
||||
a = ABS(a);
|
||||
b = ABS(b);
|
||||
for (shift = 0; !((a | b) & 0x01); shift++)
|
||||
a >>= 1, b >>= 1;
|
||||
|
||||
while (a > 0)
|
||||
{
|
||||
while (!(a & 0x01))
|
||||
a >>= 1;
|
||||
while (!(b & 0x01))
|
||||
b >>= 1;
|
||||
if (a >= b)
|
||||
a = (a - b) >> 1;
|
||||
else
|
||||
b = (b - a) >> 1;
|
||||
}
|
||||
return b << shift;
|
||||
}
|
||||
|
||||
/** Calculate a + b. */
|
||||
MMAL_RATIONAL_T mmal_rational_add(MMAL_RATIONAL_T a, MMAL_RATIONAL_T b)
|
||||
{
|
||||
MMAL_RATIONAL_T result;
|
||||
int32_t g = gcd(a.den, b.den);
|
||||
a.den /= g;
|
||||
a.num = a.num * (b.den / g) + b.num * a.den;
|
||||
g = gcd(a.num, g);
|
||||
a.num /= g;
|
||||
a.den *= b.den / g;
|
||||
|
||||
result.num = a.num;
|
||||
result.den = a.den;
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Calculate a - b. */
|
||||
MMAL_RATIONAL_T mmal_rational_subtract(MMAL_RATIONAL_T a, MMAL_RATIONAL_T b)
|
||||
{
|
||||
b.num = -b.num;
|
||||
return mmal_rational_add(a, b);
|
||||
}
|
||||
|
||||
/** Calculate a * b */
|
||||
MMAL_RATIONAL_T mmal_rational_multiply(MMAL_RATIONAL_T a, MMAL_RATIONAL_T b)
|
||||
{
|
||||
MMAL_RATIONAL_T result;
|
||||
int32_t gcd1 = gcd(a.num, b.den);
|
||||
int32_t gcd2 = gcd(b.num, a.den);
|
||||
result.num = (a.num / gcd1) * (b.num / gcd2);
|
||||
result.den = (a.den / gcd2) * (b.den / gcd1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Calculate a / b */
|
||||
MMAL_RATIONAL_T mmal_rational_divide(MMAL_RATIONAL_T a, MMAL_RATIONAL_T b)
|
||||
{
|
||||
MMAL_RATIONAL_T result;
|
||||
int32_t gcd1, gcd2;
|
||||
|
||||
if (b.num == 0)
|
||||
{
|
||||
vcos_assert(0);
|
||||
return a;
|
||||
}
|
||||
|
||||
if (a.num == 0)
|
||||
return a;
|
||||
|
||||
gcd1 = gcd(a.num, b.num);
|
||||
gcd2 = gcd(b.den, a.den);
|
||||
result.num = (a.num / gcd1) * (b.den / gcd2);
|
||||
result.den = (a.den / gcd2) * (b.num / gcd1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Convert a rational number to a signed 32-bit Q16 number. */
|
||||
int32_t mmal_rational_to_fixed_16_16(MMAL_RATIONAL_T rational)
|
||||
{
|
||||
int64_t result = (int64_t)rational.num << 16;
|
||||
if (rational.den)
|
||||
result /= rational.den;
|
||||
|
||||
if (result > INT_MAX)
|
||||
result = INT_MAX;
|
||||
else if (result < INT_MIN)
|
||||
result = INT_MIN;
|
||||
|
||||
return (int32_t)result;
|
||||
}
|
||||
|
||||
/** Convert a rational number to a signed 32-bit Q16 number. */
|
||||
MMAL_RATIONAL_T mmal_rational_from_fixed_16_16(int32_t fixed)
|
||||
{
|
||||
MMAL_RATIONAL_T result = { fixed, Q16_ONE };
|
||||
mmal_rational_simplify(&result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Reduce a rational number to it's simplest form. */
|
||||
void mmal_rational_simplify(MMAL_RATIONAL_T *rational)
|
||||
{
|
||||
int g = gcd(rational->num, rational->den);
|
||||
rational->num /= g;
|
||||
rational->den /= g;
|
||||
}
|
||||
118
interface/mmal/util/mmal_util_rational.h
Normal file
118
interface/mmal/util/mmal_util_rational.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef MMAL_UTIL_RATIONAL_H
|
||||
#define MMAL_UTIL_RATIONAL_H
|
||||
|
||||
#include "interface/mmal/mmal_types.h"
|
||||
|
||||
/** \defgroup MmalRationalUtilities Rational Utility Functions
|
||||
* \ingroup MmalUtilities
|
||||
* The rational utility functions allow easy manipulation of rational numbers.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Add 2 rational numbers.
|
||||
* It is assumed that both input rational numbers are in
|
||||
* their simplest form.
|
||||
*
|
||||
* @param a First operand
|
||||
* @param b Second operand
|
||||
*
|
||||
* @return a + b
|
||||
*/
|
||||
MMAL_RATIONAL_T mmal_rational_add(MMAL_RATIONAL_T a, MMAL_RATIONAL_T b);
|
||||
|
||||
/** Subtract 2 rational numbers.
|
||||
* It is assumed that both input rational numbers are in
|
||||
* their simplest form.
|
||||
*
|
||||
* @param a First operand
|
||||
* @param b Second operand
|
||||
*
|
||||
* @return a - b
|
||||
*/
|
||||
MMAL_RATIONAL_T mmal_rational_subtract(MMAL_RATIONAL_T a, MMAL_RATIONAL_T b);
|
||||
|
||||
/** Multiply 2 rational numbers.
|
||||
* It is assumed that both input rational numbers are in
|
||||
* their simplest form.
|
||||
*
|
||||
* @param a First operand
|
||||
* @param b Second operand
|
||||
*
|
||||
* @return a * b
|
||||
*/
|
||||
MMAL_RATIONAL_T mmal_rational_multiply(MMAL_RATIONAL_T a, MMAL_RATIONAL_T b);
|
||||
|
||||
/** Divide 2 rational numbers.
|
||||
* It is assumed that both input rational numbers are in
|
||||
* their simplest form.
|
||||
*
|
||||
* @param a First operand
|
||||
* @param b Second operand
|
||||
*
|
||||
* @return a / b
|
||||
*/
|
||||
MMAL_RATIONAL_T mmal_rational_divide(MMAL_RATIONAL_T a, MMAL_RATIONAL_T b);
|
||||
|
||||
/** Convert a rational number to a 32-bit signed Q16 number.
|
||||
* Saturation will occur for rational numbers with an absolute
|
||||
* value greater than 32768.
|
||||
*
|
||||
* @param rational Rational number to convert
|
||||
*
|
||||
* @return 32-bit signed Q16 number
|
||||
*/
|
||||
int32_t mmal_rational_to_fixed_16_16(MMAL_RATIONAL_T rational);
|
||||
|
||||
/** Convert a signed 32-bit Q16 number to a rational number.
|
||||
*
|
||||
* @param fixed Signed 32-bit Q16 number to convert
|
||||
*
|
||||
* @return Rational number
|
||||
*/
|
||||
MMAL_RATIONAL_T mmal_rational_from_fixed_16_16(int32_t fixed);
|
||||
|
||||
/** Reduce a rational number to it's simplest form.
|
||||
*
|
||||
* @param rational Rational number to simplify
|
||||
*/
|
||||
void mmal_rational_simplify(MMAL_RATIONAL_T *rational);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
add_library(mmal_vc_client SHARED mmal_vc_client.c mmal_vc_shm.c mmal_vc_api.c mmal_vc_opaque_alloc.c mmal_vc_msgnames.c)
|
||||
add_library(mmal_vc_client SHARED mmal_vc_client.c mmal_vc_shm.c mmal_vc_api.c mmal_vc_opaque_alloc.c mmal_vc_msgnames.c mmal_vc_api_drm.c)
|
||||
target_link_libraries(mmal_vc_client vchiq_arm vcos)
|
||||
|
||||
if(BUILD_MMAL_APPS)
|
||||
|
||||
@@ -40,6 +40,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/** Private information for MMAL VC components
|
||||
*/
|
||||
|
||||
typedef enum MMAL_ZEROLEN_CHECK_T
|
||||
{
|
||||
ZEROLEN_NOT_INITIALIZED,
|
||||
ZEROLEN_COMPATIBLE,
|
||||
ZEROLEN_INCOMPATIBLE
|
||||
} MMAL_ZEROLEN_CHECK_T;
|
||||
|
||||
typedef enum MMAL_PORT_FLUSH_CHECK_T
|
||||
{
|
||||
PORT_FLUSH_NOT_INITIALIZED,
|
||||
PORT_FLUSH_COMPATIBLE,
|
||||
PORT_FLUSH_INCOMPATIBLE
|
||||
} MMAL_PORT_FLUSH_CHECK_T;
|
||||
|
||||
typedef struct MMAL_PORT_MODULE_T
|
||||
{
|
||||
uint32_t magic;
|
||||
@@ -53,6 +68,8 @@ typedef struct MMAL_PORT_MODULE_T
|
||||
MMAL_BOOL_T is_zero_copy;
|
||||
MMAL_BOOL_T zero_copy_workaround;
|
||||
|
||||
MMAL_BOOL_T sent_data_on_port;
|
||||
|
||||
MMAL_PORT_T *connected; /**< Connected port if any */
|
||||
} MMAL_PORT_MODULE_T;
|
||||
|
||||
@@ -81,7 +98,7 @@ MMAL_STATUS_T mmal_vc_get_version(uint32_t *major, uint32_t *minor, uint32_t *mi
|
||||
MMAL_STATUS_T status;
|
||||
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
|
||||
MMAL_WORKER_GET_VERSION, &msg, &len);
|
||||
MMAL_WORKER_GET_VERSION, &msg, &len, MMAL_FALSE);
|
||||
|
||||
if (status != MMAL_SUCCESS)
|
||||
return status;
|
||||
@@ -105,7 +122,7 @@ MMAL_STATUS_T mmal_vc_get_stats(MMAL_VC_STATS_T *stats, int reset)
|
||||
MMAL_STATUS_T status = mmal_vc_sendwait_message(mmal_vc_get_client(),
|
||||
&msg.header, sizeof(msg),
|
||||
MMAL_WORKER_GET_STATS,
|
||||
&msg, &len);
|
||||
&msg, &len, MMAL_FALSE);
|
||||
|
||||
|
||||
if (status == MMAL_SUCCESS)
|
||||
@@ -131,7 +148,7 @@ static MMAL_STATUS_T mmal_vc_port_requirements_set(MMAL_PORT_T *port)
|
||||
msg.param.enable.port = *port;
|
||||
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
|
||||
MMAL_WORKER_PORT_ACTION, &reply, &replylen);
|
||||
MMAL_WORKER_PORT_ACTION, &reply, &replylen, MMAL_FALSE);
|
||||
if (status == MMAL_SUCCESS)
|
||||
{
|
||||
vcos_assert(replylen == sizeof(reply));
|
||||
@@ -161,7 +178,7 @@ static MMAL_STATUS_T mmal_vc_port_requirements_get(MMAL_PORT_T *port)
|
||||
LOG_TRACE("get port requirements (%i:%i)", port->type, port->index);
|
||||
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
|
||||
MMAL_WORKER_PORT_INFO_GET, &reply, &replylen);
|
||||
MMAL_WORKER_PORT_INFO_GET, &reply, &replylen, MMAL_FALSE);
|
||||
if (status == MMAL_SUCCESS)
|
||||
{
|
||||
vcos_assert(replylen == sizeof(reply));
|
||||
@@ -219,7 +236,7 @@ static MMAL_STATUS_T mmal_vc_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb
|
||||
msg.param.enable.port = *port;
|
||||
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
|
||||
MMAL_WORKER_PORT_ACTION, &reply, &replylen);
|
||||
MMAL_WORKER_PORT_ACTION, &reply, &replylen, MMAL_FALSE);
|
||||
if (status == MMAL_SUCCESS)
|
||||
{
|
||||
vcos_assert(replylen == sizeof(reply));
|
||||
@@ -257,7 +274,7 @@ static MMAL_STATUS_T mmal_vc_port_disable(MMAL_PORT_T *port)
|
||||
msg.port_handle = module->port_handle;
|
||||
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
|
||||
MMAL_WORKER_PORT_ACTION, &reply, &replylen);
|
||||
MMAL_WORKER_PORT_ACTION, &reply, &replylen, MMAL_FALSE);
|
||||
if (status == MMAL_SUCCESS)
|
||||
{
|
||||
vcos_assert(replylen == sizeof(reply));
|
||||
@@ -285,8 +302,8 @@ static MMAL_STATUS_T mmal_vc_port_disable(MMAL_PORT_T *port)
|
||||
return status;
|
||||
}
|
||||
|
||||
/** Flush a port */
|
||||
static MMAL_STATUS_T mmal_vc_port_flush(MMAL_PORT_T *port)
|
||||
/** Flush a port using MMAL_WORKER_PORT_ACTION - when the port is zero-copy or no data has been sent */
|
||||
static MMAL_STATUS_T mmal_vc_port_flush_normal(MMAL_PORT_T *port)
|
||||
{
|
||||
MMAL_PORT_MODULE_T *module = port->priv->module;
|
||||
MMAL_STATUS_T status;
|
||||
@@ -299,7 +316,7 @@ static MMAL_STATUS_T mmal_vc_port_flush(MMAL_PORT_T *port)
|
||||
msg.port_handle = module->port_handle;
|
||||
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
|
||||
MMAL_WORKER_PORT_ACTION, &reply, &replylen);
|
||||
MMAL_WORKER_PORT_ACTION, &reply, &replylen, MMAL_FALSE);
|
||||
if (status == MMAL_SUCCESS)
|
||||
{
|
||||
vcos_assert(replylen == sizeof(reply));
|
||||
@@ -311,6 +328,84 @@ static MMAL_STATUS_T mmal_vc_port_flush(MMAL_PORT_T *port)
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/** Flush a port using PORT_FLUSH - generates a dummy bulk transfer to keep it in sync
|
||||
* with buffers being passed using bulk transfer */
|
||||
static MMAL_STATUS_T mmal_vc_port_flush_sync(MMAL_PORT_T *port)
|
||||
{
|
||||
MMAL_PORT_MODULE_T *module = port->priv->module;
|
||||
MMAL_STATUS_T status;
|
||||
mmal_worker_reply reply;
|
||||
MMAL_VC_CLIENT_BUFFER_CONTEXT_T client_context;
|
||||
mmal_worker_buffer_from_host *msg;
|
||||
|
||||
size_t replylen = sizeof(reply);
|
||||
|
||||
msg = &client_context.msg;
|
||||
|
||||
client_context.magic = MMAL_MAGIC;
|
||||
client_context.port = port;
|
||||
|
||||
msg->drvbuf.client_context = &client_context;
|
||||
msg->drvbuf.component_handle = module->component_handle;
|
||||
msg->drvbuf.port_handle = module->port_handle;
|
||||
msg->drvbuf.magic = MMAL_MAGIC;
|
||||
|
||||
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg->header, sizeof(*msg),
|
||||
MMAL_WORKER_PORT_FLUSH, &reply, &replylen, MMAL_TRUE);
|
||||
if (status == MMAL_SUCCESS)
|
||||
{
|
||||
vcos_assert(replylen == sizeof(reply));
|
||||
status = reply.status;
|
||||
}
|
||||
if (status != MMAL_SUCCESS)
|
||||
LOG_ERROR("failed to disable port - reason %d", status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/** Flush a port */
|
||||
static MMAL_STATUS_T mmal_vc_port_flush(MMAL_PORT_T *port)
|
||||
{
|
||||
static MMAL_PORT_FLUSH_CHECK_T is_port_flush_compatible = PORT_FLUSH_NOT_INITIALIZED;
|
||||
uint32_t major, minor, minimum;
|
||||
MMAL_STATUS_T status;
|
||||
/* Buffers sent to videocore, if not zero-copy, use vchiq bulk transfers to copy the data.
|
||||
A flush could be sent while one of these buffers is being copied. If the normal flushing method
|
||||
is used, the flush can arrive before the buffer, which causes confusion when a pre-flush buffer
|
||||
arrives after the flush. So use a special flush mode that uses a dummy vchiq transfer to synchronise
|
||||
things.
|
||||
If data has never been sent on the port, then we don't need to worry about a flush overtaking data.
|
||||
In that case, the port may not actually be set up on the other end to receive bulk transfers, so use
|
||||
the normal flushing mechanism in that case.
|
||||
*/
|
||||
|
||||
if (port->priv->module->is_zero_copy || !port->priv->module->sent_data_on_port)
|
||||
return mmal_vc_port_flush_normal(port);
|
||||
|
||||
if (is_port_flush_compatible == PORT_FLUSH_NOT_INITIALIZED)
|
||||
{
|
||||
status = mmal_vc_get_version(&major, &minor, &minimum);
|
||||
if (major >= 15)
|
||||
{
|
||||
is_port_flush_compatible = PORT_FLUSH_COMPATIBLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Version number of MMAL Server incompatible. Required Major:14 Minor: 2 \
|
||||
or Greater. Current Major %d , Minor %d",major,minor);
|
||||
is_port_flush_compatible = PORT_FLUSH_INCOMPATIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_port_flush_compatible == PORT_FLUSH_COMPATIBLE)
|
||||
return mmal_vc_port_flush_sync(port);
|
||||
else
|
||||
return mmal_vc_port_flush_normal(port);
|
||||
}
|
||||
|
||||
|
||||
/** Connect 2 ports together */
|
||||
static MMAL_STATUS_T mmal_vc_port_connect(MMAL_PORT_T *port, MMAL_PORT_T *other_port)
|
||||
{
|
||||
@@ -335,7 +430,7 @@ static MMAL_STATUS_T mmal_vc_port_connect(MMAL_PORT_T *port, MMAL_PORT_T *other_
|
||||
}
|
||||
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
|
||||
MMAL_WORKER_PORT_ACTION, &reply, &replylen);
|
||||
MMAL_WORKER_PORT_ACTION, &reply, &replylen, MMAL_FALSE);
|
||||
if (status == MMAL_SUCCESS)
|
||||
{
|
||||
vcos_assert(replylen == sizeof(reply));
|
||||
@@ -378,8 +473,12 @@ static void mmal_vc_do_callback(MMAL_COMPONENT_T *component)
|
||||
return; /* Will happen when a port gets disabled */
|
||||
|
||||
port = (MMAL_PORT_T *)buffer->priv->component_data;
|
||||
buffer->data = mmal_vc_shm_lock(buffer->data, port->priv->module->zero_copy_workaround);
|
||||
|
||||
/* Catch and report any transmission error */
|
||||
if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED)
|
||||
mmal_event_error_send(port->component, MMAL_EIO);
|
||||
|
||||
buffer->data = mmal_vc_shm_lock(buffer->data, port->priv->module->zero_copy_workaround);
|
||||
mmal_port_buffer_header_callback(port, buffer);
|
||||
}
|
||||
|
||||
@@ -405,14 +504,6 @@ static void mmal_vc_port_send_callback(mmal_worker_buffer_from_host *msg)
|
||||
vcos_assert(port->priv->module->magic == MMAL_MAGIC);
|
||||
mmal_vc_msg_to_buffer_header(buffer, msg);
|
||||
|
||||
if (port->priv->module->is_zero_copy &&
|
||||
(port->capabilities & MMAL_PORT_CAPABILITY_PASSTHROUGH))
|
||||
{
|
||||
/* We do not have our own payload but are reusing one from an input port */
|
||||
buffer->alloc_size = msg->buffer_header.alloc_size;
|
||||
buffer->data = msg->buffer_header.data;
|
||||
}
|
||||
|
||||
/* Queue the callback so it is delivered by the action thread */
|
||||
buffer->priv->component_data = (void *)port;
|
||||
mmal_queue_put(port->component->priv->module->callback_queue, buffer);
|
||||
@@ -429,6 +520,9 @@ static MMAL_STATUS_T mmal_vc_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *
|
||||
MMAL_VC_CLIENT_BUFFER_CONTEXT_T *client_context;
|
||||
mmal_worker_buffer_from_host *msg;
|
||||
uint32_t length;
|
||||
uint32_t msgid = MMAL_WORKER_BUFFER_FROM_HOST;
|
||||
uint32_t major, minor, minimum;
|
||||
static MMAL_ZEROLEN_CHECK_T is_vc_zerolength_compatible = ZEROLEN_NOT_INITIALIZED;
|
||||
|
||||
vcos_assert(port);
|
||||
vcos_assert(module);
|
||||
@@ -513,9 +607,39 @@ static MMAL_STATUS_T mmal_vc_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *
|
||||
if (module->is_zero_copy)
|
||||
length = 0;
|
||||
|
||||
if (is_vc_zerolength_compatible == ZEROLEN_NOT_INITIALIZED)
|
||||
{
|
||||
status = mmal_vc_get_version(&major, &minor, &minimum);
|
||||
if ((major > 12 ) || ((major == 12) && (minor >= 2)))
|
||||
{
|
||||
is_vc_zerolength_compatible = ZEROLEN_COMPATIBLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Version number of MMAL Server incompatible. Required Major:12 Minor: 2 \
|
||||
or Greater. Current Major %d , Minor %d",major,minor);
|
||||
is_vc_zerolength_compatible = ZEROLEN_INCOMPATIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
if ((is_vc_zerolength_compatible == ZEROLEN_COMPATIBLE) && !(module->is_zero_copy) && !length
|
||||
&& (msg->buffer_header.flags & MMAL_BUFFER_HEADER_FLAG_EOS))
|
||||
{
|
||||
length = 8;
|
||||
msgid = MMAL_WORKER_BUFFER_FROM_HOST_ZEROLEN;
|
||||
}
|
||||
|
||||
if (length)
|
||||
{
|
||||
// We're doing a bulk transfer. Note this so that flushes know
|
||||
// they need to use the more cumbersome fake-bulk-transfer mechanism
|
||||
// to guarantee correct ordering.
|
||||
port->priv->module->sent_data_on_port = MMAL_TRUE;
|
||||
}
|
||||
|
||||
status = mmal_vc_send_message(mmal_vc_get_client(), &msg->header, sizeof(*msg),
|
||||
buffer->data + buffer->offset, length,
|
||||
MMAL_WORKER_BUFFER_FROM_HOST);
|
||||
msgid);
|
||||
if (status != MMAL_SUCCESS)
|
||||
{
|
||||
LOG_INFO("failed %d", status);
|
||||
@@ -539,7 +663,7 @@ static MMAL_STATUS_T mmal_vc_component_disable(MMAL_COMPONENT_T *component)
|
||||
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
|
||||
MMAL_WORKER_COMPONENT_DISABLE,
|
||||
&reply, &replylen);
|
||||
&reply, &replylen, MMAL_FALSE);
|
||||
|
||||
if (status == MMAL_SUCCESS)
|
||||
{
|
||||
@@ -570,7 +694,7 @@ static MMAL_STATUS_T mmal_vc_component_enable(MMAL_COMPONENT_T *component)
|
||||
msg.component_handle = component->priv->module->component_handle;
|
||||
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
|
||||
MMAL_WORKER_COMPONENT_ENABLE, &reply, &replylen);
|
||||
MMAL_WORKER_COMPONENT_ENABLE, &reply, &replylen, MMAL_FALSE);
|
||||
|
||||
if (status == MMAL_SUCCESS)
|
||||
{
|
||||
@@ -600,7 +724,7 @@ static MMAL_STATUS_T mmal_vc_component_destroy(MMAL_COMPONENT_T *component)
|
||||
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
|
||||
MMAL_WORKER_COMPONENT_DESTROY,
|
||||
&reply, &replylen);
|
||||
&reply, &replylen, MMAL_FALSE);
|
||||
|
||||
if (status == MMAL_SUCCESS)
|
||||
{
|
||||
@@ -617,11 +741,15 @@ static MMAL_STATUS_T mmal_vc_component_destroy(MMAL_COMPONENT_T *component)
|
||||
mmal_ports_free(component->input, component->input_num);
|
||||
if(component->output_num)
|
||||
mmal_ports_free(component->output, component->output_num);
|
||||
if(component->clock_num)
|
||||
mmal_ports_free(component->clock, component->clock_num);
|
||||
|
||||
vcos_free(component->priv->module);
|
||||
component->priv->module = NULL;
|
||||
|
||||
fail:
|
||||
// no longer require videocore
|
||||
mmal_vc_release();
|
||||
mmal_vc_deinit();
|
||||
return status;
|
||||
}
|
||||
@@ -631,14 +759,14 @@ MMAL_STATUS_T mmal_vc_consume_mem(size_t size, uint32_t *handle)
|
||||
MMAL_STATUS_T status;
|
||||
mmal_worker_consume_mem req;
|
||||
mmal_worker_consume_mem reply;
|
||||
size_t len;
|
||||
size_t len = sizeof(reply);
|
||||
|
||||
req.size = (uint32_t) size;
|
||||
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(),
|
||||
&req.header, sizeof(req),
|
||||
MMAL_WORKER_CONSUME_MEM,
|
||||
&reply, &len);
|
||||
&reply, &len, MMAL_FALSE);
|
||||
if (status == MMAL_SUCCESS)
|
||||
{
|
||||
vcos_assert(len == sizeof(reply));
|
||||
@@ -648,6 +776,22 @@ MMAL_STATUS_T mmal_vc_consume_mem(size_t size, uint32_t *handle)
|
||||
return status;
|
||||
}
|
||||
|
||||
MMAL_STATUS_T mmal_vc_lmk(uint32_t alloc_size)
|
||||
{
|
||||
MMAL_STATUS_T status;
|
||||
mmal_worker_lmk req;
|
||||
mmal_worker_lmk reply;
|
||||
size_t len = sizeof(reply);
|
||||
|
||||
req.alloc_size = alloc_size;
|
||||
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(),
|
||||
&req.header, sizeof(req),
|
||||
MMAL_WORKER_LMK,
|
||||
&reply, &len, MMAL_FALSE);
|
||||
return status;
|
||||
}
|
||||
|
||||
MMAL_STATUS_T mmal_vc_get_core_stats(MMAL_CORE_STATISTICS_T *stats,
|
||||
MMAL_STATS_RESULT_T *result,
|
||||
char *name,
|
||||
@@ -672,7 +816,7 @@ MMAL_STATUS_T mmal_vc_get_core_stats(MMAL_CORE_STATISTICS_T *stats,
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(),
|
||||
&req.header, sizeof(req),
|
||||
MMAL_WORKER_GET_CORE_STATS_FOR_PORT,
|
||||
&reply, &len);
|
||||
&reply, &len, MMAL_FALSE);
|
||||
|
||||
if (status == MMAL_SUCCESS)
|
||||
{
|
||||
@@ -702,7 +846,7 @@ static MMAL_STATUS_T mmal_vc_port_info_get(MMAL_PORT_T *port)
|
||||
LOG_TRACE("get port info (%i:%i)", port->type, port->index);
|
||||
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
|
||||
MMAL_WORKER_PORT_INFO_GET, &reply, &replylen);
|
||||
MMAL_WORKER_PORT_INFO_GET, &reply, &replylen, MMAL_FALSE);
|
||||
if (status == MMAL_SUCCESS)
|
||||
{
|
||||
vcos_assert(replylen == sizeof(reply));
|
||||
@@ -723,8 +867,8 @@ static MMAL_STATUS_T mmal_vc_port_info_get(MMAL_PORT_T *port)
|
||||
port->buffer_size_min = reply.port.buffer_size_min;
|
||||
port->buffer_size_recommended = reply.port.buffer_size_recommended;
|
||||
port->buffer_size = reply.port.buffer_size;
|
||||
port->is_enabled = reply.port.is_enabled;
|
||||
port->buffer_alignment_min = reply.port.buffer_alignment_min;
|
||||
port->is_enabled = reply.port.is_enabled;
|
||||
port->capabilities = reply.port.capabilities;
|
||||
reply.format.extradata = port->format->extradata;
|
||||
reply.format.es = port->format->es;
|
||||
@@ -771,7 +915,7 @@ static MMAL_STATUS_T mmal_vc_port_info_set(MMAL_PORT_T *port)
|
||||
LOG_TRACE("set port info (%i:%i)", port->type, port->index);
|
||||
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
|
||||
MMAL_WORKER_PORT_INFO_SET, &reply, &replylen);
|
||||
MMAL_WORKER_PORT_INFO_SET, &reply, &replylen, MMAL_FALSE);
|
||||
if (status == MMAL_SUCCESS)
|
||||
{
|
||||
vcos_assert(replylen == sizeof(reply));
|
||||
@@ -791,8 +935,8 @@ static MMAL_STATUS_T mmal_vc_port_info_set(MMAL_PORT_T *port)
|
||||
port->buffer_size_min = reply.port.buffer_size_min;
|
||||
port->buffer_size_recommended = reply.port.buffer_size_recommended;
|
||||
port->buffer_size = reply.port.buffer_size;
|
||||
port->is_enabled = reply.port.is_enabled;
|
||||
port->buffer_alignment_min = reply.port.buffer_alignment_min;
|
||||
port->is_enabled = reply.port.is_enabled;
|
||||
port->capabilities = reply.port.capabilities;
|
||||
reply.format.extradata = port->format->extradata;
|
||||
reply.format.es = port->format->es;
|
||||
@@ -887,10 +1031,11 @@ static MMAL_STATUS_T mmal_vc_port_parameter_set(MMAL_PORT_T *port, const MMAL_PA
|
||||
|
||||
msg.component_handle = module->component_handle;
|
||||
msg.port_handle = module->port_handle;
|
||||
/* coverity[overrun-buffer-arg] */
|
||||
memcpy(&msg.param, param, param->size);
|
||||
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, msglen,
|
||||
MMAL_WORKER_PORT_PARAMETER_SET, &reply, &replylen);
|
||||
MMAL_WORKER_PORT_PARAMETER_SET, &reply, &replylen, MMAL_FALSE);
|
||||
|
||||
if (status == MMAL_SUCCESS)
|
||||
{
|
||||
@@ -938,7 +1083,7 @@ static MMAL_STATUS_T mmal_vc_port_parameter_get(MMAL_PORT_T *port, MMAL_PARAMETE
|
||||
msg.param = *param;
|
||||
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
|
||||
MMAL_WORKER_PORT_PARAMETER_GET, &reply, &replylen);
|
||||
MMAL_WORKER_PORT_PARAMETER_GET, &reply, &replylen, MMAL_FALSE);
|
||||
if (status == MMAL_SUCCESS)
|
||||
{
|
||||
status = reply.status;
|
||||
@@ -967,6 +1112,7 @@ static MMAL_STATUS_T mmal_vc_port_parameter_get(MMAL_PORT_T *port, MMAL_PARAMETE
|
||||
if (status == MMAL_ENOSPC)
|
||||
{
|
||||
/* Copy only as much as we have space for but report true size of parameter */
|
||||
/* coverity[overrun-buffer-arg] */
|
||||
memcpy(param, &reply.param, param->size);
|
||||
param->size = reply.param.size;
|
||||
}
|
||||
@@ -996,20 +1142,26 @@ static uint8_t *mmal_vc_port_payload_alloc(MMAL_PORT_T *port, uint32_t payload_s
|
||||
if (port->format->encoding == MMAL_ENCODING_OPAQUE &&
|
||||
module->is_zero_copy)
|
||||
{
|
||||
MMAL_OPAQUE_IMAGE_HANDLE_T h = mmal_vc_opaque_alloc();
|
||||
MMAL_OPAQUE_IMAGE_HANDLE_T h = mmal_vc_opaque_alloc_desc(port->name);
|
||||
can_deref = MMAL_FALSE;
|
||||
ret = (void*)h;
|
||||
if (!ret)
|
||||
{
|
||||
LOG_ERROR("%s: failed to allocate %d bytes opaque memory",
|
||||
port->name, payload_size);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
else if (module->is_zero_copy)
|
||||
{
|
||||
ret = mmal_vc_shm_alloc(payload_size);
|
||||
if (!ret)
|
||||
{
|
||||
LOG_ERROR("%s: failed to allocate %d bytes of shared memory",
|
||||
port->name, payload_size);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
@@ -1074,6 +1226,7 @@ static MMAL_STATUS_T mmal_vc_component_create(const char *name, MMAL_COMPONENT_T
|
||||
}
|
||||
|
||||
msg.client_component = component;
|
||||
/* coverity[secure_coding] Length tested above */
|
||||
strcpy(msg.name, basename);
|
||||
#ifdef __linux__
|
||||
msg.pid = getpid();
|
||||
@@ -1086,9 +1239,11 @@ static MMAL_STATUS_T mmal_vc_component_create(const char *name, MMAL_COMPONENT_T
|
||||
name, status, mmal_status_to_string(status));
|
||||
return status;
|
||||
}
|
||||
// claim VC for entire duration of component.
|
||||
status = mmal_vc_use();
|
||||
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
|
||||
MMAL_WORKER_COMPONENT_CREATE, &reply, &replylen);
|
||||
MMAL_WORKER_COMPONENT_CREATE, &reply, &replylen, MMAL_FALSE);
|
||||
|
||||
vcos_log_info("%s: %s: handle 0x%x status %d reply status %d",
|
||||
__FUNCTION__, name, reply.component_handle, status, reply.status);
|
||||
@@ -1103,21 +1258,26 @@ static MMAL_STATUS_T mmal_vc_component_create(const char *name, MMAL_COMPONENT_T
|
||||
{
|
||||
LOG_ERROR("failed to create component '%s' (%i:%s)", name, status,
|
||||
mmal_status_to_string(status));
|
||||
mmal_vc_release();
|
||||
mmal_vc_deinit();
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Component has been created, allocate our context. */
|
||||
status = MMAL_ENOMEM;
|
||||
ports_num = 1 + reply.input_num + reply.output_num;
|
||||
ports_num = 1 + reply.input_num + reply.output_num + reply.clock_num;
|
||||
module = vcos_calloc(1, sizeof(*module) + ports_num * sizeof(*module->ports), "mmal_vc_module");
|
||||
if (!module)
|
||||
{
|
||||
mmal_worker_component_destroy msg;
|
||||
mmal_worker_reply reply;
|
||||
size_t replylen = sizeof(reply);
|
||||
mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
|
||||
MMAL_WORKER_COMPONENT_DESTROY, &reply, &replylen);
|
||||
MMAL_STATUS_T destroy_status;
|
||||
|
||||
destroy_status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
|
||||
MMAL_WORKER_COMPONENT_DESTROY, &reply, &replylen, MMAL_FALSE);
|
||||
vcos_assert(destroy_status == MMAL_SUCCESS);
|
||||
mmal_vc_release();
|
||||
mmal_vc_deinit();
|
||||
return status;
|
||||
}
|
||||
@@ -1141,6 +1301,11 @@ static MMAL_STATUS_T mmal_vc_component_create(const char *name, MMAL_COMPONENT_T
|
||||
if (!component->output)
|
||||
goto fail;
|
||||
component->output_num = reply.output_num;
|
||||
component->clock = mmal_ports_alloc(component, reply.clock_num, MMAL_PORT_TYPE_CLOCK,
|
||||
sizeof(MMAL_PORT_MODULE_T));
|
||||
if (!component->clock)
|
||||
goto fail;
|
||||
component->clock_num = reply.clock_num;
|
||||
|
||||
/* We want to do the buffer callbacks to the client into a separate thread.
|
||||
* We'll need to queue these callbacks and have an action which does the actual callback. */
|
||||
@@ -1153,7 +1318,6 @@ static MMAL_STATUS_T mmal_vc_component_create(const char *name, MMAL_COMPONENT_T
|
||||
|
||||
LOG_TRACE(" handle %i", reply.component_handle);
|
||||
|
||||
component->control->type = MMAL_PORT_TYPE_CONTROL;
|
||||
module->ports[module->ports_num] = component->control->priv->module;
|
||||
module->ports[module->ports_num]->port = component->control;
|
||||
module->ports[module->ports_num]->component_handle = module->component_handle;
|
||||
@@ -1161,7 +1325,6 @@ static MMAL_STATUS_T mmal_vc_component_create(const char *name, MMAL_COMPONENT_T
|
||||
|
||||
for (i = 0; i < component->input_num; i++, module->ports_num++)
|
||||
{
|
||||
component->input[i]->type = MMAL_PORT_TYPE_INPUT;
|
||||
module->ports[module->ports_num] = component->input[i]->priv->module;
|
||||
module->ports[module->ports_num]->port = component->input[i];
|
||||
module->ports[module->ports_num]->component_handle = module->component_handle;
|
||||
@@ -1169,12 +1332,18 @@ static MMAL_STATUS_T mmal_vc_component_create(const char *name, MMAL_COMPONENT_T
|
||||
|
||||
for (i = 0; i < component->output_num; i++, module->ports_num++)
|
||||
{
|
||||
component->output[i]->type = MMAL_PORT_TYPE_OUTPUT;
|
||||
module->ports[module->ports_num] = component->output[i]->priv->module;
|
||||
module->ports[module->ports_num]->port = component->output[i];
|
||||
module->ports[module->ports_num]->component_handle = module->component_handle;
|
||||
}
|
||||
|
||||
for (i = 0; i < component->clock_num; i++, module->ports_num++)
|
||||
{
|
||||
module->ports[module->ports_num] = component->clock[i]->priv->module;
|
||||
module->ports[module->ports_num]->port = component->clock[i];
|
||||
module->ports[module->ports_num]->component_handle = module->component_handle;
|
||||
}
|
||||
|
||||
/* Get the ports info */
|
||||
for (i = 0; i < module->ports_num; i++)
|
||||
{
|
||||
|
||||
@@ -34,9 +34,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* via MMAL itself.
|
||||
*/
|
||||
|
||||
#include "mmal_types.h"
|
||||
#include "mmal_parameters.h"
|
||||
#include "mmal_port.h"
|
||||
#include "interface/mmal/mmal_types.h"
|
||||
#include "interface/mmal/mmal_parameters.h"
|
||||
#include "interface/mmal/mmal_port.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -132,6 +132,10 @@ typedef enum
|
||||
|
||||
MMAL_STATUS_T mmal_vc_init(void);
|
||||
void mmal_vc_deinit(void);
|
||||
|
||||
MMAL_STATUS_T mmal_vc_use(void);
|
||||
MMAL_STATUS_T mmal_vc_release(void);
|
||||
|
||||
MMAL_STATUS_T mmal_vc_get_version(uint32_t *major, uint32_t *minor, uint32_t *minimum);
|
||||
MMAL_STATUS_T mmal_vc_get_stats(MMAL_VC_STATS_T *stats, int reset);
|
||||
|
||||
@@ -175,6 +179,11 @@ MMAL_STATUS_T mmal_vc_get_core_stats(MMAL_CORE_STATISTICS_T *stats,
|
||||
*/
|
||||
MMAL_STATUS_T mmal_vc_consume_mem(size_t size, uint32_t *handle);
|
||||
|
||||
/** Trigger LMK action from VC, for diagnostics.
|
||||
* @internal
|
||||
*/
|
||||
MMAL_STATUS_T mmal_vc_lmk(uint32_t alloc_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
77
interface/mmal/vc/mmal_vc_api_drm.c
Normal file
77
interface/mmal/vc/mmal_vc_api_drm.c
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "mmal_vc_api_drm.h"
|
||||
#include "mmal_vc_api.h"
|
||||
#include "interface/mmal/mmal_logging.h"
|
||||
#include "interface/mmal/mmal.h"
|
||||
#include "mmal_vc_api.h"
|
||||
#include "mmal_vc_msgs.h"
|
||||
#include "mmal_vc_client_priv.h"
|
||||
#include "mmal_vc_opaque_alloc.h"
|
||||
#include "mmal_vc_shm.h"
|
||||
#include "interface/mmal/util/mmal_util.h"
|
||||
#include "interface/mmal/core/mmal_component_private.h"
|
||||
#include "interface/mmal/core/mmal_port_private.h"
|
||||
#include "interface/mmal/core/mmal_buffer_private.h"
|
||||
#include "interface/vcos/vcos.h"
|
||||
|
||||
|
||||
int mmal_vc_drm_get_time(unsigned int * time)
|
||||
{
|
||||
MMAL_STATUS_T status;
|
||||
mmal_worker_msg_header req;
|
||||
mmal_worker_drm_get_time_reply reply;
|
||||
size_t len = sizeof(reply);
|
||||
status = mmal_vc_init();
|
||||
if (status != MMAL_SUCCESS) return status;
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(),
|
||||
&req, sizeof(req),
|
||||
MMAL_WORKER_DRM_GET_TIME,
|
||||
&reply, &len, MMAL_FALSE);
|
||||
*time = reply.time;
|
||||
mmal_vc_deinit();
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int mmal_vc_drm_get_lhs32(unsigned char * into)
|
||||
{
|
||||
MMAL_STATUS_T status;
|
||||
mmal_worker_msg_header req;
|
||||
mmal_worker_drm_get_lhs32_reply reply;
|
||||
size_t len = sizeof(reply);
|
||||
status = mmal_vc_init();
|
||||
if (status != MMAL_SUCCESS) return status;
|
||||
|
||||
status = mmal_vc_sendwait_message(mmal_vc_get_client(),
|
||||
&req, sizeof(req),
|
||||
MMAL_WORKER_DRM_GET_LHS32,
|
||||
&reply, &len, MMAL_FALSE);
|
||||
memcpy(into, reply.secret, 32);
|
||||
mmal_vc_deinit();
|
||||
return status;
|
||||
}
|
||||
@@ -24,3 +24,32 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef MMAL_VC_API_DRM_H
|
||||
#define MMAL_VC_API_DRM_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Public API for MMAL VC client. (Divx DRM part)
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Reads the current clock (in microseconds) into the "time" variable.
|
||||
// Returns zero on success, nonszero on failure
|
||||
int mmal_vc_drm_get_time(unsigned int * time);
|
||||
|
||||
// Reads the local hardware secret into the "into" variable (needs to be 32 bytes of space for this)
|
||||
// Returns 0 on success, nonzero on failure
|
||||
// Usage:
|
||||
// unsigned char buffer[32];
|
||||
// success = mmal_vc_divx_drm_get_lhs(buffer);
|
||||
int mmal_vc_drm_get_lhs32(unsigned char * into);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -73,6 +73,7 @@ typedef struct
|
||||
struct MMAL_CLIENT_T
|
||||
{
|
||||
int refcount;
|
||||
int usecount;
|
||||
VCOS_MUTEX_T lock;
|
||||
VCHIQ_SERVICE_HANDLE_T service;
|
||||
MMAL_WAITPOOL_T waitpool;
|
||||
@@ -149,9 +150,12 @@ static MMAL_WAITER_T *get_waiter(MMAL_CLIENT_T *client)
|
||||
if (client->waitpool.waiters[i].inuse == 0)
|
||||
break;
|
||||
}
|
||||
vcos_assert(i != MAX_WAITERS); /* If we get here, semaphore not working */
|
||||
waiter = client->waitpool.waiters+i;
|
||||
waiter->inuse = 1;
|
||||
/* If this fails, the semaphore is not working */
|
||||
if (vcos_verify(i != MAX_WAITERS))
|
||||
{
|
||||
waiter = client->waitpool.waiters+i;
|
||||
waiter->inuse = 1;
|
||||
}
|
||||
vcos_mutex_unlock(&client->lock);
|
||||
|
||||
return waiter;
|
||||
@@ -181,6 +185,9 @@ static MMAL_PORT_T *mmal_vc_port_by_number(MMAL_COMPONENT_T *component, uint32_t
|
||||
case MMAL_PORT_TYPE_OUTPUT:
|
||||
vcos_assert(number < component->output_num);
|
||||
return component->output[number];
|
||||
case MMAL_PORT_TYPE_CLOCK:
|
||||
vcos_assert(number < component->clock_num);
|
||||
return component->clock[number];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -255,6 +262,39 @@ error:
|
||||
vchiq_release_message(service, vchiq_header);
|
||||
}
|
||||
|
||||
static MMAL_STATUS_T mmal_vc_use_internal(MMAL_CLIENT_T *client)
|
||||
{
|
||||
MMAL_STATUS_T status = MMAL_SUCCESS;
|
||||
vcos_mutex_lock(&client->lock);
|
||||
if(client->usecount++ == 0)
|
||||
{
|
||||
if(vchiq_use_service(client->service) != VCHIQ_SUCCESS)
|
||||
{
|
||||
client->usecount--;
|
||||
status = MMAL_EIO;
|
||||
}
|
||||
}
|
||||
vcos_mutex_unlock(&client->lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
static MMAL_STATUS_T mmal_vc_release_internal(MMAL_CLIENT_T *client)
|
||||
{
|
||||
MMAL_STATUS_T status = MMAL_SUCCESS;
|
||||
vcos_mutex_lock(&client->lock);
|
||||
if(--client->usecount == 0)
|
||||
{
|
||||
if(vchiq_release_service(client->service) != VCHIQ_SUCCESS)
|
||||
{
|
||||
client->usecount++;
|
||||
status = MMAL_EIO;
|
||||
}
|
||||
}
|
||||
vcos_mutex_unlock(&client->lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/** Callback invoked by VCHIQ
|
||||
*/
|
||||
static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
|
||||
@@ -264,8 +304,6 @@ static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
|
||||
{
|
||||
LOG_TRACE("reason %d", reason);
|
||||
|
||||
vchiq_use_service(service);
|
||||
|
||||
switch (reason)
|
||||
{
|
||||
case VCHIQ_MESSAGE_AVAILABLE:
|
||||
@@ -281,6 +319,13 @@ static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
|
||||
vcos_assert(msg->drvbuf.client_context);
|
||||
vcos_assert(msg->drvbuf.client_context->magic == MMAL_MAGIC);
|
||||
|
||||
/* If the buffer is referencing another, need to replicate it here
|
||||
* in order to use the reference buffer's payload and ensure the
|
||||
* reference is not released prematurely */
|
||||
if (msg->has_reference)
|
||||
mmal_buffer_header_replicate(msg->drvbuf.client_context->buffer,
|
||||
msg->drvbuf_ref.client_context->buffer);
|
||||
|
||||
/* Sanity check the size of the transfer so we don't overrun our buffer */
|
||||
if (!vcos_verify(msg->buffer_header.offset + msg->buffer_header.length <=
|
||||
msg->drvbuf.client_context->buffer->alloc_size))
|
||||
@@ -288,13 +333,15 @@ static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
|
||||
LOG_TRACE("buffer too small (%i, %i)",
|
||||
msg->buffer_header.offset + msg->buffer_header.length,
|
||||
msg->drvbuf.client_context->buffer->alloc_size);
|
||||
msg->buffer_header.length = 0; // FIXME: set a buffer flag to signal error
|
||||
msg->buffer_header.length = 0; /* FIXME: set a buffer flag to signal error */
|
||||
msg->drvbuf.client_context->callback(msg);
|
||||
vchiq_release_message(service, vchiq_header);
|
||||
break;
|
||||
}
|
||||
|
||||
if (msg->buffer_header.length != 0 && !msg->is_zero_copy)
|
||||
/*To handle VC to HOST filled buffer callback of EOS buffer to receive in sync with data buffers*/
|
||||
if (!msg->is_zero_copy &&
|
||||
(msg->buffer_header.length != 0 ||
|
||||
(msg->buffer_header.flags & MMAL_BUFFER_HEADER_FLAG_EOS)))
|
||||
{
|
||||
/* a buffer full of data for us to process */
|
||||
VCHIQ_STATUS_T vst = VCHIQ_SUCCESS;
|
||||
@@ -302,7 +349,11 @@ static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
|
||||
msg->buffer_header.offset, msg->buffer_header.length);
|
||||
int len = msg->buffer_header.length;
|
||||
len = (len+3) & (~3);
|
||||
|
||||
|
||||
if (!len && (msg->buffer_header.flags & MMAL_BUFFER_HEADER_FLAG_EOS))
|
||||
{
|
||||
len = 8;
|
||||
}
|
||||
if (!msg->payload_in_message)
|
||||
{
|
||||
/* buffer transferred using vchiq bulk xfer */
|
||||
@@ -376,14 +427,16 @@ static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
|
||||
* has emptied the buffer before we can recycle it, otherwise we
|
||||
* end up feeding the copro with buffers it cannot handle.
|
||||
*/
|
||||
#ifdef VCOS_LOGGING_ENABLED
|
||||
mmal_worker_buffer_from_host *msg = (mmal_worker_buffer_from_host *)context;
|
||||
#endif
|
||||
LOG_TRACE("bulk tx done: %p, %d", msg->buffer_header.data, msg->buffer_header.length);
|
||||
}
|
||||
break;
|
||||
case VCHIQ_BULK_RECEIVE_DONE:
|
||||
{
|
||||
VCHIQ_HEADER_T *vchiq_header = (VCHIQ_HEADER_T *)context;
|
||||
mmal_worker_msg_header *msg_hdr = (mmal_worker_msg_header*)vchiq_header->data;
|
||||
VCHIQ_HEADER_T *header = (VCHIQ_HEADER_T *)context;
|
||||
mmal_worker_msg_header *msg_hdr = (mmal_worker_msg_header*)header->data;
|
||||
if (msg_hdr->msgid == MMAL_WORKER_BUFFER_TO_HOST)
|
||||
{
|
||||
mmal_worker_buffer_from_host *msg = (mmal_worker_buffer_from_host *)msg_hdr;
|
||||
@@ -400,19 +453,19 @@ static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
|
||||
mmal_port_event_send(port, msg->delayed_buffer);
|
||||
LOG_DEBUG("event bulk rx done, length %d", msg->length);
|
||||
}
|
||||
vchiq_release_message(service, vchiq_header);
|
||||
vchiq_release_message(service, header);
|
||||
}
|
||||
break;
|
||||
case VCHIQ_BULK_RECEIVE_ABORTED:
|
||||
{
|
||||
VCHIQ_HEADER_T *vchiq_header = (VCHIQ_HEADER_T *)context;
|
||||
mmal_worker_msg_header *msg_hdr = (mmal_worker_msg_header*)vchiq_header->data;
|
||||
VCHIQ_HEADER_T *header = (VCHIQ_HEADER_T *)context;
|
||||
mmal_worker_msg_header *msg_hdr = (mmal_worker_msg_header*)header->data;
|
||||
if (msg_hdr->msgid == MMAL_WORKER_BUFFER_TO_HOST)
|
||||
{
|
||||
mmal_worker_buffer_from_host *msg = (mmal_worker_buffer_from_host *)msg_hdr;
|
||||
LOG_TRACE("bulk rx aborted: %p, %d", msg->buffer_header.data, msg->buffer_header.length);
|
||||
vcos_assert(msg->drvbuf.client_context->magic == MMAL_MAGIC);
|
||||
msg->buffer_header.length = 0; /* FIXME: set a buffer flag to signal error */
|
||||
msg->buffer_header.flags |= MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED;
|
||||
msg->drvbuf.client_context->callback(msg);
|
||||
}
|
||||
else
|
||||
@@ -422,10 +475,10 @@ static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
|
||||
|
||||
vcos_assert(port);
|
||||
LOG_DEBUG("event bulk rx aborted");
|
||||
msg->delayed_buffer->length = 0; /* FIXME: set a buffer flag to signal error */
|
||||
msg->delayed_buffer->flags |= MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED;
|
||||
mmal_port_event_send(port, msg->delayed_buffer);
|
||||
}
|
||||
vchiq_release_message(service, vchiq_header);
|
||||
vchiq_release_message(service, header);
|
||||
}
|
||||
break;
|
||||
case VCHIQ_BULK_TRANSMIT_ABORTED:
|
||||
@@ -433,14 +486,12 @@ static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
|
||||
mmal_worker_buffer_from_host *msg = (mmal_worker_buffer_from_host *)context;
|
||||
LOG_INFO("bulk tx aborted: %p, %d", msg->buffer_header.data, msg->buffer_header.length);
|
||||
vcos_assert(msg->drvbuf.client_context->magic == MMAL_MAGIC);
|
||||
msg->buffer_header.length = 0; // FIXME: set a buffer flag to signal error
|
||||
msg->drvbuf.client_context->callback(msg);
|
||||
/* Nothing to do as the VC side will release the buffer and notify us of the error */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
vchiq_release_service(service);
|
||||
|
||||
return VCHIQ_SUCCESS;
|
||||
}
|
||||
@@ -453,13 +504,15 @@ static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
|
||||
* @param msgid message id
|
||||
* @param dest destination for reply
|
||||
* @param destlen size of destination, updated with actual length
|
||||
* @param send_dummy_bulk whether to send a dummy bulk transfer
|
||||
*/
|
||||
MMAL_STATUS_T mmal_vc_sendwait_message(struct MMAL_CLIENT_T *client,
|
||||
mmal_worker_msg_header *msg_header,
|
||||
size_t size,
|
||||
uint32_t msgid,
|
||||
void *dest,
|
||||
size_t *destlen)
|
||||
size_t *destlen,
|
||||
MMAL_BOOL_T send_dummy_bulk)
|
||||
{
|
||||
MMAL_STATUS_T ret;
|
||||
MMAL_WAITER_T *waiter;
|
||||
@@ -475,6 +528,9 @@ MMAL_STATUS_T mmal_vc_sendwait_message(struct MMAL_CLIENT_T *client,
|
||||
return MMAL_EINVAL;
|
||||
}
|
||||
|
||||
if (send_dummy_bulk)
|
||||
vcos_mutex_lock(&client->bulk_lock);
|
||||
|
||||
waiter = get_waiter(client);
|
||||
msg_header->msgid = msgid;
|
||||
msg_header->u.waiter = waiter;
|
||||
@@ -483,16 +539,38 @@ MMAL_STATUS_T mmal_vc_sendwait_message(struct MMAL_CLIENT_T *client,
|
||||
waiter->dest = dest;
|
||||
waiter->destlen = *destlen;
|
||||
LOG_TRACE("wait %p, reply to %p", waiter, dest);
|
||||
vchiq_use_service(client->service);
|
||||
mmal_vc_use_internal(client);
|
||||
|
||||
vst = vchiq_queue_message(client->service, elems, 1);
|
||||
|
||||
if (vst != VCHIQ_SUCCESS)
|
||||
{
|
||||
ret = MMAL_EIO;
|
||||
if (send_dummy_bulk)
|
||||
vcos_mutex_unlock(&client->bulk_lock);
|
||||
goto fail_msg;
|
||||
}
|
||||
|
||||
if (send_dummy_bulk)
|
||||
{
|
||||
uint32_t data_size = 8;
|
||||
/* The data is just some dummy bytes so it's fine for it to be static */
|
||||
static uint8_t data[8];
|
||||
vst = vchiq_queue_bulk_transmit(client->service, data, data_size, msg_header);
|
||||
|
||||
vcos_mutex_unlock(&client->bulk_lock);
|
||||
|
||||
if (!vcos_verify(vst == VCHIQ_SUCCESS))
|
||||
{
|
||||
LOG_ERROR("failed bulk transmit");
|
||||
/* This really should not happen and if it does, things will go wrong as
|
||||
* we've already queued the vchiq message above. */
|
||||
vcos_assert(0);
|
||||
ret = MMAL_EIO;
|
||||
goto fail_msg;
|
||||
}
|
||||
}
|
||||
|
||||
/* now wait for the reply...
|
||||
*
|
||||
* FIXME: we could do with a timeout here. Need to be careful to cancel
|
||||
@@ -500,8 +578,7 @@ MMAL_STATUS_T mmal_vc_sendwait_message(struct MMAL_CLIENT_T *client,
|
||||
*/
|
||||
vcos_semaphore_wait(&waiter->sem);
|
||||
|
||||
vchiq_release_service(client->service);
|
||||
|
||||
mmal_vc_release_internal(client);
|
||||
LOG_TRACE("got reply (len %i/%i)", (int)*destlen, (int)waiter->destlen);
|
||||
*destlen = waiter->destlen;
|
||||
|
||||
@@ -509,13 +586,17 @@ MMAL_STATUS_T mmal_vc_sendwait_message(struct MMAL_CLIENT_T *client,
|
||||
return MMAL_SUCCESS;
|
||||
|
||||
fail_msg:
|
||||
vchiq_release_service(client->service);
|
||||
mmal_vc_release_internal(client);
|
||||
|
||||
release_waiter(client, waiter);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Send a message and do not wait for a reply.
|
||||
*
|
||||
* @note
|
||||
* This function should only be called from within a mmal component, so
|
||||
* vchiq_use/release_service calls aren't required (dealt with at higher level).
|
||||
*
|
||||
* @param client client to send message for
|
||||
* @param msg_header message header to send
|
||||
@@ -546,8 +627,6 @@ MMAL_STATUS_T mmal_vc_send_message(MMAL_CLIENT_T *client,
|
||||
msg_header->msgid = msgid;
|
||||
msg_header->magic = MMAL_MAGIC;
|
||||
|
||||
vchiq_use_service(client->service);
|
||||
|
||||
vst = vchiq_queue_message(client->service, elems, 1);
|
||||
|
||||
if (vst != VCHIQ_SUCCESS)
|
||||
@@ -578,21 +657,33 @@ MMAL_STATUS_T mmal_vc_send_message(MMAL_CLIENT_T *client,
|
||||
}
|
||||
}
|
||||
|
||||
// TBD - do we need to release later if this is a message which gets and async response.
|
||||
vchiq_release_service(client->service);
|
||||
|
||||
return MMAL_SUCCESS;
|
||||
|
||||
error:
|
||||
vchiq_release_service(client->service);
|
||||
return MMAL_EIO;
|
||||
}
|
||||
|
||||
MMAL_STATUS_T mmal_vc_use(void)
|
||||
{
|
||||
MMAL_STATUS_T status = MMAL_ENOTCONN;
|
||||
if(client.inited)
|
||||
status = mmal_vc_use_internal(&client);
|
||||
return status;
|
||||
}
|
||||
|
||||
MMAL_STATUS_T mmal_vc_release(void)
|
||||
{
|
||||
MMAL_STATUS_T status = MMAL_ENOTCONN;
|
||||
if(client.inited)
|
||||
status = mmal_vc_release_internal(&client);
|
||||
return status;
|
||||
}
|
||||
|
||||
MMAL_STATUS_T mmal_vc_init(void)
|
||||
{
|
||||
VCHIQ_SERVICE_PARAMS_T vchiq_params;
|
||||
MMAL_BOOL_T vchiq_initialised = 0, waitpool_initialised = 0;
|
||||
MMAL_BOOL_T service_initialised = 0, bulk_lock_initialised = 0;
|
||||
MMAL_BOOL_T service_initialised = 0;
|
||||
MMAL_STATUS_T status = MMAL_EIO;
|
||||
VCHIQ_STATUS_T vchiq_status;
|
||||
int count;
|
||||
@@ -636,18 +727,16 @@ MMAL_STATUS_T mmal_vc_init(void)
|
||||
vchiq_params.version = WORKER_VER_MAJOR;
|
||||
vchiq_params.version_min = WORKER_VER_MINIMUM;
|
||||
|
||||
vchiq_status = vchiq_open_service_params(mmal_vchiq_instance, &vchiq_params, &client.service);
|
||||
vchiq_status = vchiq_open_service(mmal_vchiq_instance, &vchiq_params, &client.service);
|
||||
if (vchiq_status != VCHIQ_SUCCESS)
|
||||
{
|
||||
LOG_ERROR("could not open vchiq service");
|
||||
status = MMAL_EIO;
|
||||
goto error;
|
||||
}
|
||||
client.usecount = 1; /* usecount set to 1 by the open call. */
|
||||
service_initialised = 1;
|
||||
|
||||
// not using the service immediately, so release it.
|
||||
vchiq_release_service(client.service);
|
||||
|
||||
status = create_waitpool(&client.waitpool);
|
||||
if (status != MMAL_SUCCESS)
|
||||
{
|
||||
@@ -662,20 +751,24 @@ MMAL_STATUS_T mmal_vc_init(void)
|
||||
status = MMAL_ENOSPC;
|
||||
goto error;
|
||||
}
|
||||
bulk_lock_initialised = 1;
|
||||
|
||||
client.inited = 1;
|
||||
|
||||
vcos_mutex_unlock(&client.lock);
|
||||
/* assume we're not using VC immediately. Do this outside the lock */
|
||||
mmal_vc_release();
|
||||
|
||||
|
||||
return MMAL_SUCCESS;
|
||||
|
||||
error:
|
||||
if (bulk_lock_initialised)
|
||||
vcos_mutex_delete(&client.bulk_lock);
|
||||
if (waitpool_initialised)
|
||||
destroy_waitpool(&client.waitpool);
|
||||
if (service_initialised)
|
||||
vchiq_remove_service(client.service);
|
||||
{
|
||||
client.usecount = 0;
|
||||
vchiq_close_service(client.service);
|
||||
}
|
||||
if (vchiq_initialised)
|
||||
vchiq_shutdown(mmal_vchiq_instance);
|
||||
vcos_log_unregister(VCOS_LOG_CATEGORY);
|
||||
@@ -700,11 +793,11 @@ void mmal_vc_deinit(void)
|
||||
|
||||
vcos_mutex_delete(&client.bulk_lock);
|
||||
destroy_waitpool(&client.waitpool);
|
||||
vchiq_remove_service(client.service);
|
||||
vchiq_close_service(client.service);
|
||||
vchiq_shutdown(mmal_vchiq_instance);
|
||||
vcos_log_unregister(VCOS_LOG_CATEGORY);
|
||||
|
||||
client.service = NULL;
|
||||
client.service = VCHIQ_SERVICE_HANDLE_INVALID;
|
||||
client.inited = 0;
|
||||
vcos_mutex_unlock(&client.lock);
|
||||
}
|
||||
|
||||
@@ -65,7 +65,8 @@ MMAL_STATUS_T mmal_vc_sendwait_message(MMAL_CLIENT_T *client,
|
||||
size_t size,
|
||||
uint32_t msgid,
|
||||
void *dest,
|
||||
size_t *destlen);
|
||||
size_t *destlen,
|
||||
MMAL_BOOL_T send_dummy_bulk);
|
||||
|
||||
MMAL_STATUS_T mmal_vc_send_message(MMAL_CLIENT_T *client,
|
||||
mmal_worker_msg_header *header, size_t size,
|
||||
|
||||
@@ -56,6 +56,12 @@ const char *mmal_msgname(uint32_t id)
|
||||
MSGNAME(GET_CORE_STATS_FOR_PORT),
|
||||
MSGNAME(OPAQUE_ALLOCATOR),
|
||||
MSGNAME(CONSUME_MEM),
|
||||
MSGNAME(LMK),
|
||||
MSGNAME(OPAQUE_ALLOCATOR_DESC),
|
||||
MSGNAME(DRM_GET_LHS32),
|
||||
MSGNAME(DRM_GET_TIME),
|
||||
MSGNAME(BUFFER_FROM_HOST_ZEROLEN),
|
||||
MSGNAME(PORT_FLUSH),
|
||||
{ 0, NULL },
|
||||
};
|
||||
vcos_static_assert(sizeof(msgnames)/sizeof(msgnames[0]) == MMAL_WORKER_MSG_LAST);
|
||||
|
||||
@@ -40,12 +40,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define MMAL_CONTROL_FOURCC() VCHIQ_MAKE_FOURCC('m','m','a','l')
|
||||
|
||||
/* Major version indicates binary backwards compatiblity */
|
||||
#define WORKER_VER_MAJOR 8
|
||||
/* Minor version is increased for new APIs where backwards
|
||||
* binary compatibility is retained for existing APIs */
|
||||
#define WORKER_VER_MAJOR 15
|
||||
#define WORKER_VER_MINIMUM 10
|
||||
/* Minor version is not used normally.
|
||||
*/
|
||||
#define WORKER_VER_MINOR 1
|
||||
#ifndef WORKER_VER_MINIMUM
|
||||
#define WORKER_VER_MINIMUM WORKER_VER_MAJOR
|
||||
#endif
|
||||
|
||||
#define VIDEOCORE_PREFIX "vc"
|
||||
@@ -95,7 +95,13 @@ typedef enum {
|
||||
MMAL_WORKER_OPAQUE_ALLOCATOR,
|
||||
/* VC debug mode only - due to security, denial of service implications */
|
||||
MMAL_WORKER_CONSUME_MEM,
|
||||
MMAL_WORKER_MSG_LAST,
|
||||
MMAL_WORKER_LMK,
|
||||
MMAL_WORKER_OPAQUE_ALLOCATOR_DESC,
|
||||
MMAL_WORKER_DRM_GET_LHS32,
|
||||
MMAL_WORKER_DRM_GET_TIME,
|
||||
MMAL_WORKER_BUFFER_FROM_HOST_ZEROLEN,
|
||||
MMAL_WORKER_PORT_FLUSH,
|
||||
MMAL_WORKER_MSG_LAST
|
||||
} MMAL_WORKER_CMD_T;
|
||||
|
||||
/** Every message has one of these at the start.
|
||||
@@ -157,9 +163,9 @@ typedef struct
|
||||
mmal_worker_msg_header header;
|
||||
MMAL_STATUS_T status;
|
||||
uint32_t component_handle; /** Handle on VideoCore for component */
|
||||
uint32_t control_num; /**< Number of control ports */
|
||||
uint32_t input_num; /**< Number of input ports */
|
||||
uint32_t output_num; /**< Number of output ports */
|
||||
uint32_t clock_num; /**< Number of clock ports */
|
||||
} mmal_worker_component_create_reply;
|
||||
vcos_static_assert(sizeof(mmal_worker_component_create_reply) <= MMAL_WORKER_MAX_MSG_LEN);
|
||||
|
||||
@@ -236,6 +242,22 @@ typedef struct
|
||||
MMAL_STATUS_T status;
|
||||
} mmal_worker_reply;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mmal_worker_msg_header header;
|
||||
MMAL_STATUS_T status;
|
||||
uint8_t secret[32];
|
||||
} mmal_worker_drm_get_lhs32_reply;
|
||||
vcos_static_assert(sizeof(mmal_worker_drm_get_lhs32_reply) <= MMAL_WORKER_MAX_MSG_LEN);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mmal_worker_msg_header header;
|
||||
MMAL_STATUS_T status;
|
||||
uint32_t time;
|
||||
} mmal_worker_drm_get_time_reply;
|
||||
vcos_static_assert(sizeof(mmal_worker_drm_get_time_reply) <= MMAL_WORKER_MAX_MSG_LEN);
|
||||
|
||||
/** List of actions for a port */
|
||||
enum MMAL_WORKER_PORT_ACTIONS
|
||||
{
|
||||
@@ -341,11 +363,19 @@ typedef struct mmal_worker_buffer_from_host
|
||||
*/
|
||||
struct MMAL_DRIVER_BUFFER_T drvbuf;
|
||||
|
||||
/** Referenced buffer control data.
|
||||
* This is set if the buffer is referencing another
|
||||
* buffer as is the case with passthrough ports where
|
||||
* buffers on the output port reference buffers on the
|
||||
* input port. */
|
||||
struct MMAL_DRIVER_BUFFER_T drvbuf_ref;
|
||||
|
||||
/** the buffer header itself */
|
||||
MMAL_BUFFER_HEADER_T buffer_header;
|
||||
MMAL_BUFFER_HEADER_TYPE_SPECIFIC_T buffer_header_type_specific;
|
||||
|
||||
MMAL_BOOL_T is_zero_copy;
|
||||
MMAL_BOOL_T has_reference;
|
||||
|
||||
/** If the data is short enough, then send it in the control message rather
|
||||
* than using a separate VCHIQ bulk transfer.
|
||||
@@ -402,6 +432,7 @@ typedef struct
|
||||
MMAL_WORKER_OPAQUE_MEM_OP op;
|
||||
uint32_t handle;
|
||||
MMAL_STATUS_T status;
|
||||
char description[32];
|
||||
} mmal_worker_opaque_allocator;
|
||||
|
||||
/*
|
||||
@@ -436,6 +467,14 @@ typedef struct
|
||||
uint32_t handle;
|
||||
} mmal_worker_consume_mem;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mmal_worker_msg_header header;
|
||||
/* The memory allocation size to pass to lmk, as if in a response to an
|
||||
* allocation for this amount of memory. */
|
||||
uint32_t alloc_size;
|
||||
} mmal_worker_lmk;
|
||||
|
||||
|
||||
static inline void mmal_vc_buffer_header_to_msg(mmal_worker_buffer_from_host *msg,
|
||||
MMAL_BUFFER_HEADER_T *header)
|
||||
|
||||
@@ -29,17 +29,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "mmal_vc_msgs.h"
|
||||
#include "mmal_vc_client_priv.h"
|
||||
|
||||
MMAL_OPAQUE_IMAGE_HANDLE_T mmal_vc_opaque_alloc(void)
|
||||
MMAL_OPAQUE_IMAGE_HANDLE_T mmal_vc_opaque_alloc_desc(const char *description)
|
||||
{
|
||||
MMAL_STATUS_T ret;
|
||||
MMAL_OPAQUE_IMAGE_HANDLE_T h = 0;
|
||||
mmal_worker_opaque_allocator msg;
|
||||
size_t len = sizeof(msg);
|
||||
msg.op = MMAL_WORKER_OPAQUE_MEM_ALLOC;
|
||||
vcos_safe_strcpy(msg.description, description, sizeof(msg.description), 0);
|
||||
ret = mmal_vc_sendwait_message(mmal_vc_get_client(),
|
||||
&msg.header, sizeof(msg),
|
||||
MMAL_WORKER_OPAQUE_ALLOCATOR,
|
||||
&msg, &len);
|
||||
MMAL_WORKER_OPAQUE_ALLOCATOR_DESC,
|
||||
&msg, &len, MMAL_FALSE);
|
||||
if (ret == MMAL_SUCCESS)
|
||||
{
|
||||
h = msg.handle;
|
||||
@@ -47,6 +48,11 @@ MMAL_OPAQUE_IMAGE_HANDLE_T mmal_vc_opaque_alloc(void)
|
||||
return h;
|
||||
}
|
||||
|
||||
MMAL_OPAQUE_IMAGE_HANDLE_T mmal_vc_opaque_alloc(void)
|
||||
{
|
||||
return mmal_vc_opaque_alloc_desc("?");
|
||||
}
|
||||
|
||||
MMAL_STATUS_T mmal_vc_opaque_acquire(unsigned int handle)
|
||||
{
|
||||
MMAL_STATUS_T ret;
|
||||
@@ -57,7 +63,7 @@ MMAL_STATUS_T mmal_vc_opaque_acquire(unsigned int handle)
|
||||
ret = mmal_vc_sendwait_message(mmal_vc_get_client(),
|
||||
&msg.header, sizeof(msg),
|
||||
MMAL_WORKER_OPAQUE_ALLOCATOR,
|
||||
&msg, &len);
|
||||
&msg, &len, MMAL_FALSE);
|
||||
if (ret == MMAL_SUCCESS)
|
||||
ret = msg.status;
|
||||
return ret;
|
||||
@@ -73,7 +79,7 @@ MMAL_STATUS_T mmal_vc_opaque_release(unsigned int handle)
|
||||
ret = mmal_vc_sendwait_message(mmal_vc_get_client(),
|
||||
&msg.header, sizeof(msg),
|
||||
MMAL_WORKER_OPAQUE_ALLOCATOR,
|
||||
&msg, &len);
|
||||
&msg, &len, MMAL_FALSE);
|
||||
if (ret == MMAL_SUCCESS)
|
||||
ret = msg.status;
|
||||
return ret;
|
||||
|
||||
@@ -44,6 +44,11 @@ typedef uint32_t MMAL_OPAQUE_IMAGE_HANDLE_T;
|
||||
*/
|
||||
MMAL_OPAQUE_IMAGE_HANDLE_T mmal_vc_opaque_alloc(void);
|
||||
|
||||
/** Allocate an opaque image on VideoCore, providing a description.
|
||||
* @return allocated handle, or zero if allocation failed.
|
||||
*/
|
||||
MMAL_OPAQUE_IMAGE_HANDLE_T mmal_vc_opaque_alloc_desc(const char *description);
|
||||
|
||||
/** Release an opaque image.
|
||||
*
|
||||
* @param handle handle allocated earlier
|
||||
|
||||
@@ -130,7 +130,11 @@ static MMAL_VC_PAYLOAD_ELEM_T *mmal_vc_payload_list_find_handle(uint8_t *mem)
|
||||
MMAL_STATUS_T mmal_vc_shm_init(void)
|
||||
{
|
||||
#ifdef ENABLE_MMAL_VCSM
|
||||
vcsm_init();
|
||||
if (vcsm_init() != 0)
|
||||
{
|
||||
LOG_ERROR("could not initialize vc shared memory service");
|
||||
return MMAL_EIO;
|
||||
}
|
||||
#endif /* ENABLE_MMAL_VCSM */
|
||||
|
||||
mmal_vc_payload_list_init();
|
||||
@@ -150,7 +154,7 @@ uint8_t *mmal_vc_shm_alloc(uint32_t size)
|
||||
}
|
||||
|
||||
#ifdef ENABLE_MMAL_VCSM
|
||||
unsigned int vcsm_handle = vcsm_malloc_cache(size, VCSM_CACHE_TYPE_NONE, "mmal_vc_port buffer");
|
||||
unsigned int vcsm_handle = vcsm_malloc_cache(size, VCSM_CACHE_TYPE_HOST, "mmal_vc_port buffer");
|
||||
unsigned int vc_handle = vcsm_vc_hdl_from_hdl(vcsm_handle);
|
||||
mem = (uint8_t *)vcsm_lock( vcsm_handle );
|
||||
if (!mem || !vc_handle)
|
||||
@@ -165,6 +169,12 @@ uint8_t *mmal_vc_shm_alloc(uint32_t size)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The memory area is automatically mem-locked by vcsm's fault
|
||||
* handler when it is next used. So leave it unlocked until it
|
||||
* is needed.
|
||||
*/
|
||||
vcsm_unlock_hdl(vcsm_handle);
|
||||
|
||||
payload_elem->mem = mem;
|
||||
payload_elem->handle = (void *)vcsm_handle;
|
||||
payload_elem->vc_handle = (void *)vc_handle;
|
||||
|
||||
@@ -30,6 +30,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef _VC_TOUCHSERV_DEFS_H
|
||||
#define _VC_TOUCHSERV_DEFS_H
|
||||
|
||||
#define VC_TOUCHSERV_VER 1
|
||||
|
||||
|
||||
/*! Message header */
|
||||
typedef struct {
|
||||
|
||||
@@ -25,6 +25,12 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* \file
|
||||
*
|
||||
* \brief Contains the protypes for the interface functions.
|
||||
*/
|
||||
|
||||
#ifndef CONNECTION_H_
|
||||
#define CONNECTION_H_
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// MPHI videocore message driver
|
||||
|
||||
#ifndef _VCHI_MESSAGE_H_
|
||||
#define _VCHI_MESSAGE_H_
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Contains the protypes for the vchi functions.
|
||||
|
||||
#ifndef VCHI_H_
|
||||
#define VCHI_H_
|
||||
|
||||
@@ -39,6 +41,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
Global defs
|
||||
*****************************************************************************/
|
||||
|
||||
#define VCHI_SERVICE_HANDLE_INVALID 0
|
||||
|
||||
#define VCHI_BULK_ROUND_UP(x) ((((unsigned long)(x))+VCHI_BULK_ALIGN-1) & ~(VCHI_BULK_ALIGN-1))
|
||||
#define VCHI_BULK_ROUND_DOWN(x) (((unsigned long)(x)) & ~(VCHI_BULK_ALIGN-1))
|
||||
#define VCHI_BULK_ALIGN_NBYTES(x) (VCHI_BULK_ALIGNED(x) ? 0 : (VCHI_BULK_ALIGN - ((unsigned long)(x) & (VCHI_BULK_ALIGN-1))))
|
||||
@@ -49,6 +53,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define VCHI_BULK_ALIGNED(x) (((unsigned long)(x) & (VCHI_BULK_ALIGN-1)) == 0)
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t version;
|
||||
uint32_t version_min;
|
||||
} VCHI_VERSION_T;
|
||||
#define VCHI_VERSION(v_) { v_, v_ }
|
||||
#define VCHI_VERSION_EX(v_,m_) { v_, m_ }
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@@ -113,6 +124,7 @@ typedef struct
|
||||
|
||||
// structure used to provide the information needed to open a server or a client
|
||||
typedef struct {
|
||||
VCHI_VERSION_T version;
|
||||
vcos_fourcc_t service_id;
|
||||
VCHI_CONNECTION_T *connection;
|
||||
uint32_t rx_fifo_size;
|
||||
@@ -128,7 +140,7 @@ typedef struct {
|
||||
typedef struct opaque_vchi_instance_handle_t *VCHI_INSTANCE_T;
|
||||
|
||||
// Opaque handle for a server or client
|
||||
typedef struct opaque_vchi_service_handle_t *VCHI_SERVICE_HANDLE_T;
|
||||
typedef unsigned int VCHI_SERVICE_HANDLE_T;
|
||||
|
||||
// Service registration & startup
|
||||
typedef void (*VCHI_SERVICE_INIT)(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections);
|
||||
@@ -190,6 +202,9 @@ extern int32_t vchi_service_open( VCHI_INSTANCE_T instance_handle,
|
||||
SERVICE_CREATION_T *setup,
|
||||
VCHI_SERVICE_HANDLE_T *handle);
|
||||
|
||||
extern int32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle,
|
||||
short *peer_version );
|
||||
|
||||
// Routine to close a named service
|
||||
extern int32_t vchi_service_close( const VCHI_SERVICE_HANDLE_T handle );
|
||||
|
||||
|
||||
@@ -25,6 +25,10 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Contains the #defines for the number of servers / clients etc, these can be
|
||||
// over-ridden from the platform makefile if needed
|
||||
|
||||
|
||||
#ifndef VCHI_CFG_H_
|
||||
#define VCHI_CFG_H_
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef VCHI_CFG_INTERNAL_H_
|
||||
#define VCHI_CFG_INTERNAL_H_
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Contains global defs used by submodules within vchi
|
||||
|
||||
#ifndef VCHI_COMMON_H_
|
||||
#define VCHI_COMMON_H_
|
||||
|
||||
|
||||
12
interface/vchiq_arm/vchiq_cfg.h
Normal file → Executable file
12
interface/vchiq_arm/vchiq_cfg.h
Normal file → Executable file
@@ -23,17 +23,19 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
*/
|
||||
|
||||
#ifndef VCHIQ_CFG_H
|
||||
#define VCHIQ_CFG_H
|
||||
|
||||
#define VCHIQ_MAGIC VCHIQ_MAKE_FOURCC('V','C','H','I')
|
||||
#define VCHIQ_MAGIC VCHIQ_MAKE_FOURCC('V', 'C', 'H', 'I')
|
||||
/* The version of VCHIQ - change with any non-trivial change */
|
||||
#define VCHIQ_VERSION 2
|
||||
/* The minimum compatible version - update to match VCHIQ_VERSION with any incompatible change */
|
||||
#define VCHIQ_VERSION_MIN 2
|
||||
#define VCHIQ_VERSION 5
|
||||
/* The minimum compatible version - update to match VCHIQ_VERSION with any
|
||||
** incompatible change */
|
||||
#define VCHIQ_VERSION_MIN 3
|
||||
|
||||
#define VCHIQ_MAX_STATES 2
|
||||
#define VCHIQ_MAX_SERVICES 4096
|
||||
#define VCHIQ_MAX_SLOTS 128
|
||||
#define VCHIQ_MAX_SLOTS_PER_SIDE 64
|
||||
|
||||
75
interface/vchiq_arm/vchiq_if.h
Normal file → Executable file
75
interface/vchiq_arm/vchiq_if.h
Normal file → Executable file
@@ -23,20 +23,22 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
*/
|
||||
|
||||
#ifndef VCHIQ_IF_H
|
||||
#define VCHIQ_IF_H
|
||||
|
||||
#include "interface/vchi/vchi_mh.h"
|
||||
|
||||
#define VCHIQ_SERVICE_HANDLE_INVALID 0
|
||||
|
||||
#define VCHIQ_SLOT_SIZE 4096
|
||||
#define VCHIQ_MAX_MSG_SIZE (VCHIQ_SLOT_SIZE - sizeof(VCHIQ_HEADER_T))
|
||||
#define VCHIQ_CHANNEL_SIZE VCHIQ_MAX_MSG_SIZE /* For backwards compatibility */
|
||||
|
||||
#define VCHIQ_MAKE_FOURCC(x0, x1, x2, x3) (((x0) << 24) | ((x1) << 16) | ((x2) << 8) | (x3))
|
||||
#define VCHIQ_GET_SERVICE_USERDATA(service) (service->userdata)
|
||||
#define VCHIQ_GET_SERVICE_FOURCC(service) (service->fourcc)
|
||||
#define VCHIQ_GET_SERVICE_USERDATA(service) vchiq_get_service_userdata(service)
|
||||
#define VCHIQ_GET_SERVICE_FOURCC(service) vchiq_get_service_fourcc(service)
|
||||
|
||||
typedef enum {
|
||||
VCHIQ_SERVICE_OPENED, // service, -, -
|
||||
@@ -66,7 +68,8 @@ typedef enum
|
||||
{
|
||||
VCHIQ_SERVICE_OPTION_AUTOCLOSE,
|
||||
VCHIQ_SERVICE_OPTION_SLOT_QUOTA,
|
||||
VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA
|
||||
VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA,
|
||||
VCHIQ_SERVICE_OPTION_SYNCHRONOUS
|
||||
} VCHIQ_SERVICE_OPTION_T;
|
||||
|
||||
#ifdef __HIGHC__
|
||||
@@ -94,9 +97,10 @@ typedef struct {
|
||||
int size;
|
||||
} VCHIQ_ELEMENT_T;
|
||||
|
||||
typedef const struct vchiq_service_base_struct *VCHIQ_SERVICE_HANDLE_T;
|
||||
typedef unsigned int VCHIQ_SERVICE_HANDLE_T;
|
||||
|
||||
typedef VCHIQ_STATUS_T (*VCHIQ_CALLBACK_T)(VCHIQ_REASON_T, VCHIQ_HEADER_T *, VCHIQ_SERVICE_HANDLE_T, void *);
|
||||
typedef VCHIQ_STATUS_T (*VCHIQ_CALLBACK_T)(VCHIQ_REASON_T, VCHIQ_HEADER_T *,
|
||||
VCHIQ_SERVICE_HANDLE_T, void *);
|
||||
|
||||
typedef struct vchiq_service_base_struct {
|
||||
int fourcc;
|
||||
@@ -129,12 +133,10 @@ typedef void (*VCHIQ_REMOTE_USE_CALLBACK_T)(void* cb_arg);
|
||||
extern VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *pinstance);
|
||||
extern VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance);
|
||||
extern VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance);
|
||||
extern VCHIQ_STATUS_T vchiq_add_service(VCHIQ_INSTANCE_T instance, int fourcc, VCHIQ_CALLBACK_T callback, void *userdata, VCHIQ_SERVICE_HANDLE_T *pservice);
|
||||
extern VCHIQ_STATUS_T vchiq_open_service(VCHIQ_INSTANCE_T instance, int fourcc, VCHIQ_CALLBACK_T callback, void *userdata, VCHIQ_SERVICE_HANDLE_T *pservice);
|
||||
extern VCHIQ_STATUS_T vchiq_add_service_params(VCHIQ_INSTANCE_T instance,
|
||||
extern VCHIQ_STATUS_T vchiq_add_service(VCHIQ_INSTANCE_T instance,
|
||||
const VCHIQ_SERVICE_PARAMS_T *params,
|
||||
VCHIQ_SERVICE_HANDLE_T *pservice);
|
||||
extern VCHIQ_STATUS_T vchiq_open_service_params(VCHIQ_INSTANCE_T instance,
|
||||
extern VCHIQ_STATUS_T vchiq_open_service(VCHIQ_INSTANCE_T instance,
|
||||
const VCHIQ_SERVICE_PARAMS_T *params,
|
||||
VCHIQ_SERVICE_HANDLE_T *pservice);
|
||||
extern VCHIQ_STATUS_T vchiq_close_service(VCHIQ_SERVICE_HANDLE_T service);
|
||||
@@ -142,23 +144,46 @@ extern VCHIQ_STATUS_T vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T service);
|
||||
extern VCHIQ_STATUS_T vchiq_use_service(VCHIQ_SERVICE_HANDLE_T service);
|
||||
extern VCHIQ_STATUS_T vchiq_release_service(VCHIQ_SERVICE_HANDLE_T service);
|
||||
|
||||
extern VCHIQ_STATUS_T vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T service, const VCHIQ_ELEMENT_T *elements, int count);
|
||||
extern void vchiq_release_message(VCHIQ_SERVICE_HANDLE_T service, VCHIQ_HEADER_T *header);
|
||||
extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service, const void *data, int size, void *userdata);
|
||||
extern VCHIQ_STATUS_T vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T service, void *data, int size, void *userdata);
|
||||
extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle, const void *offset, int size, void *userdata);
|
||||
extern VCHIQ_STATUS_T vchiq_queue_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle, void *offset, int size, void *userdata);
|
||||
extern VCHIQ_STATUS_T vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service, const void *data, int size, void *userdata, VCHIQ_BULK_MODE_T mode);
|
||||
extern VCHIQ_STATUS_T vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T service, void *data, int size, void *userdata, VCHIQ_BULK_MODE_T mode);
|
||||
extern VCHIQ_STATUS_T vchiq_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle, const void *offset, int size, void *userdata, VCHIQ_BULK_MODE_T mode);
|
||||
extern VCHIQ_STATUS_T vchiq_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle, void *offset, int size, void *userdata, VCHIQ_BULK_MODE_T mode);
|
||||
extern int vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T service);
|
||||
extern VCHIQ_STATUS_T vchiq_get_config(VCHIQ_INSTANCE_T instance, int config_size, VCHIQ_CONFIG_T *pconfig);
|
||||
extern VCHIQ_STATUS_T vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T service, VCHIQ_SERVICE_OPTION_T option, int value);
|
||||
extern VCHIQ_STATUS_T vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T service,
|
||||
const VCHIQ_ELEMENT_T *elements, int count);
|
||||
extern void vchiq_release_message(VCHIQ_SERVICE_HANDLE_T service,
|
||||
VCHIQ_HEADER_T *header);
|
||||
extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service,
|
||||
const void *data, int size, void *userdata);
|
||||
extern VCHIQ_STATUS_T vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T service,
|
||||
void *data, int size, void *userdata);
|
||||
extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit_handle(
|
||||
VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle,
|
||||
const void *offset, int size, void *userdata);
|
||||
extern VCHIQ_STATUS_T vchiq_queue_bulk_receive_handle(
|
||||
VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle,
|
||||
void *offset, int size, void *userdata);
|
||||
extern VCHIQ_STATUS_T vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service,
|
||||
const void *data, int size, void *userdata, VCHIQ_BULK_MODE_T mode);
|
||||
extern VCHIQ_STATUS_T vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T service,
|
||||
void *data, int size, void *userdata, VCHIQ_BULK_MODE_T mode);
|
||||
extern VCHIQ_STATUS_T vchiq_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T service,
|
||||
VCHI_MEM_HANDLE_T handle, const void *offset, int size, void *userdata,
|
||||
VCHIQ_BULK_MODE_T mode);
|
||||
extern VCHIQ_STATUS_T vchiq_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T service,
|
||||
VCHI_MEM_HANDLE_T handle, void *offset, int size, void *userdata,
|
||||
VCHIQ_BULK_MODE_T mode);
|
||||
extern int vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T service);
|
||||
extern void *vchiq_get_service_userdata(VCHIQ_SERVICE_HANDLE_T service);
|
||||
extern int vchiq_get_service_fourcc(VCHIQ_SERVICE_HANDLE_T service);
|
||||
extern VCHIQ_STATUS_T vchiq_get_config(VCHIQ_INSTANCE_T instance,
|
||||
int config_size, VCHIQ_CONFIG_T *pconfig);
|
||||
extern VCHIQ_STATUS_T vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T service,
|
||||
VCHIQ_SERVICE_OPTION_T option, int value);
|
||||
|
||||
extern VCHIQ_STATUS_T vchiq_remote_use(VCHIQ_INSTANCE_T instance, VCHIQ_REMOTE_USE_CALLBACK_T callback, void* cb_arg);
|
||||
extern VCHIQ_STATUS_T vchiq_remote_use(VCHIQ_INSTANCE_T instance,
|
||||
VCHIQ_REMOTE_USE_CALLBACK_T callback, void *cb_arg);
|
||||
extern VCHIQ_STATUS_T vchiq_remote_release(VCHIQ_INSTANCE_T instance);
|
||||
|
||||
extern VCHIQ_STATUS_T vchiq_dump_phys_mem( VCHIQ_SERVICE_HANDLE_T service, void *ptr, size_t num_bytes );
|
||||
extern VCHIQ_STATUS_T vchiq_dump_phys_mem(VCHIQ_SERVICE_HANDLE_T service,
|
||||
void *ptr, size_t num_bytes);
|
||||
|
||||
extern VCHIQ_STATUS_T vchiq_get_peer_version(VCHIQ_SERVICE_HANDLE_T handle,
|
||||
short *peer_version);
|
||||
|
||||
#endif /* VCHIQ_IF_H */
|
||||
|
||||
6
interface/vchiq_arm/vchiq_ioctl.h
Normal file → Executable file
6
interface/vchiq_arm/vchiq_ioctl.h
Normal file → Executable file
@@ -23,7 +23,7 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
*/
|
||||
|
||||
#ifndef VCHIQ_IOCTLS_H
|
||||
#define VCHIQ_IOCTLS_H
|
||||
@@ -98,8 +98,8 @@ typedef struct {
|
||||
#define VCHIQ_IOC_CREATE_SERVICE _IOWR(VCHIQ_IOC_MAGIC, 2, VCHIQ_CREATE_SERVICE_T)
|
||||
#define VCHIQ_IOC_REMOVE_SERVICE _IO(VCHIQ_IOC_MAGIC, 3)
|
||||
#define VCHIQ_IOC_QUEUE_MESSAGE _IOW(VCHIQ_IOC_MAGIC, 4, VCHIQ_QUEUE_MESSAGE_T)
|
||||
#define VCHIQ_IOC_QUEUE_BULK_TRANSMIT _IOW(VCHIQ_IOC_MAGIC, 5, VCHIQ_QUEUE_BULK_TRANSFER_T)
|
||||
#define VCHIQ_IOC_QUEUE_BULK_RECEIVE _IOW(VCHIQ_IOC_MAGIC, 6, VCHIQ_QUEUE_BULK_TRANSFER_T)
|
||||
#define VCHIQ_IOC_QUEUE_BULK_TRANSMIT _IOWR(VCHIQ_IOC_MAGIC, 5, VCHIQ_QUEUE_BULK_TRANSFER_T)
|
||||
#define VCHIQ_IOC_QUEUE_BULK_RECEIVE _IOWR(VCHIQ_IOC_MAGIC, 6, VCHIQ_QUEUE_BULK_TRANSFER_T)
|
||||
#define VCHIQ_IOC_AWAIT_COMPLETION _IOWR(VCHIQ_IOC_MAGIC, 7, VCHIQ_AWAIT_COMPLETION_T)
|
||||
#define VCHIQ_IOC_DEQUEUE_MESSAGE _IOWR(VCHIQ_IOC_MAGIC, 8, VCHIQ_DEQUEUE_MESSAGE_T)
|
||||
#define VCHIQ_IOC_GET_CLIENT_ID _IO(VCHIQ_IOC_MAGIC, 9)
|
||||
|
||||
@@ -37,6 +37,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "interface/vchi/common/endian.h"
|
||||
#include "interface/vcos/vcos.h"
|
||||
|
||||
#define IS_POWER_2(x) ((x & (x - 1)) == 0)
|
||||
#define VCHIQ_MAX_INSTANCE_SERVICES 32
|
||||
#define MSGBUF_SIZE (VCHIQ_MAX_MSG_SIZE + sizeof(VCHIQ_HEADER_T))
|
||||
|
||||
@@ -47,12 +48,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
typedef struct vchiq_service_struct
|
||||
{
|
||||
VCHIQ_SERVICE_BASE_T base;
|
||||
int handle;
|
||||
VCHIQ_SERVICE_HANDLE_T handle;
|
||||
VCHIQ_SERVICE_HANDLE_T lib_handle;
|
||||
int fd;
|
||||
VCHI_CALLBACK_T vchi_callback;
|
||||
void *peek_buf;
|
||||
int peek_size;
|
||||
int client_id;
|
||||
char is_client;
|
||||
} VCHIQ_SERVICE_T;
|
||||
|
||||
typedef struct vchiq_service_struct VCHI_SERVICE_T;
|
||||
@@ -75,7 +78,9 @@ static VCOS_LOG_LEVEL_T vchiq_default_lib_log_level = VCOS_LOG_WARN;
|
||||
static VCOS_LOG_CAT_T vchiq_lib_log_category;
|
||||
static VCOS_MUTEX_T vchiq_lib_mutex;
|
||||
static void *free_msgbufs;
|
||||
static unsigned int handle_seq;
|
||||
|
||||
vcos_static_assert(IS_POWER_2(VCHIQ_MAX_INSTANCE_SERVICES));
|
||||
|
||||
/* Local utility functions */
|
||||
static VCHIQ_INSTANCE_T
|
||||
@@ -88,7 +93,7 @@ create_service(VCHIQ_INSTANCE_T instance,
|
||||
const VCHIQ_SERVICE_PARAMS_T *params,
|
||||
VCHI_CALLBACK_T vchi_callback,
|
||||
int is_open,
|
||||
VCHIQ_SERVICE_HANDLE_T *pservice);
|
||||
VCHIQ_SERVICE_HANDLE_T *phandle);
|
||||
|
||||
static int
|
||||
fill_peek_buf(VCHI_SERVICE_T *service,
|
||||
@@ -106,10 +111,25 @@ is_valid_instance(VCHIQ_INSTANCE_T instance)
|
||||
return (instance == &vchiq_instance) && (instance->initialised > 0);
|
||||
}
|
||||
|
||||
static __inline int
|
||||
is_valid_service(VCHIQ_SERVICE_T *service)
|
||||
static inline VCHIQ_SERVICE_T *
|
||||
handle_to_service(VCHIQ_SERVICE_HANDLE_T handle)
|
||||
{
|
||||
return ((service != NULL) && (service->fd != VCHIQ_INVALID_HANDLE));
|
||||
return &vchiq_instance.services[handle & (VCHIQ_MAX_INSTANCE_SERVICES - 1)];
|
||||
}
|
||||
|
||||
static VCHIQ_SERVICE_T *
|
||||
find_service_by_handle(VCHIQ_SERVICE_HANDLE_T handle)
|
||||
{
|
||||
VCHIQ_SERVICE_T *service;
|
||||
|
||||
service = handle_to_service(handle);
|
||||
if (service && (service->lib_handle != handle))
|
||||
service = NULL;
|
||||
|
||||
if (!service)
|
||||
vcos_log_info("Invalid service handle 0x%x", handle);
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -150,10 +170,10 @@ vchiq_shutdown(VCHIQ_INSTANCE_T instance)
|
||||
|
||||
for (i = 0; i < instance->used_services; i++)
|
||||
{
|
||||
if (instance->services[i].handle != VCHIQ_INVALID_HANDLE)
|
||||
if (instance->services[i].lib_handle != VCHIQ_SERVICE_HANDLE_INVALID)
|
||||
{
|
||||
vchiq_remove_service(&instance->services[i].base);
|
||||
instance->services[i].handle = VCHIQ_INVALID_HANDLE;
|
||||
vchiq_remove_service(instance->services[i].lib_handle);
|
||||
instance->services[i].lib_handle = VCHIQ_SERVICE_HANDLE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,6 +215,8 @@ VCHIQ_STATUS_T
|
||||
vchiq_connect(VCHIQ_INSTANCE_T instance)
|
||||
{
|
||||
VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
|
||||
VCOS_THREAD_ATTR_T attrs;
|
||||
int ret;
|
||||
|
||||
vcos_log_trace( "%s called", __func__ );
|
||||
|
||||
@@ -203,68 +225,35 @@ vchiq_connect(VCHIQ_INSTANCE_T instance)
|
||||
|
||||
vcos_mutex_lock(&instance->mutex);
|
||||
|
||||
if (!instance->connected)
|
||||
if (instance->connected)
|
||||
goto out;
|
||||
|
||||
ret = ioctl(instance->fd, VCHIQ_IOC_CONNECT, 0);
|
||||
if (ret != 0)
|
||||
{
|
||||
int ret = ioctl(instance->fd, VCHIQ_IOC_CONNECT, 0);
|
||||
if (ret == 0)
|
||||
{
|
||||
VCOS_THREAD_ATTR_T attrs;
|
||||
instance->connected = 1;
|
||||
vcos_thread_attr_init(&attrs);
|
||||
vcos_thread_create(&instance->completion_thread, "VCHIQ completion",
|
||||
&attrs, completion_thread, instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = VCHIQ_ERROR;
|
||||
}
|
||||
status = VCHIQ_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
vcos_mutex_unlock(&instance->mutex);
|
||||
vcos_thread_attr_init(&attrs);
|
||||
if (vcos_thread_create(&instance->completion_thread, "VCHIQ completion",
|
||||
&attrs, completion_thread, instance) != VCOS_SUCCESS)
|
||||
{
|
||||
status = VCHIQ_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
instance->connected = 1;
|
||||
|
||||
out:
|
||||
vcos_mutex_unlock(&instance->mutex);
|
||||
return status;
|
||||
}
|
||||
|
||||
VCHIQ_STATUS_T
|
||||
vchiq_add_service(VCHIQ_INSTANCE_T instance,
|
||||
int fourcc,
|
||||
VCHIQ_CALLBACK_T callback,
|
||||
void *userdata,
|
||||
VCHIQ_SERVICE_HANDLE_T *pservice)
|
||||
{
|
||||
VCHIQ_SERVICE_PARAMS_T params;
|
||||
|
||||
params.fourcc = fourcc;
|
||||
params.callback = callback;
|
||||
params.userdata = userdata;
|
||||
params.version = 0;
|
||||
params.version_min = 0;
|
||||
|
||||
return vchiq_add_service_params(instance, ¶ms, pservice);
|
||||
}
|
||||
|
||||
VCHIQ_STATUS_T
|
||||
vchiq_open_service(VCHIQ_INSTANCE_T instance,
|
||||
int fourcc,
|
||||
VCHIQ_CALLBACK_T callback,
|
||||
void *userdata,
|
||||
VCHIQ_SERVICE_HANDLE_T *pservice)
|
||||
{
|
||||
VCHIQ_SERVICE_PARAMS_T params;
|
||||
|
||||
params.fourcc = fourcc;
|
||||
params.callback = callback;
|
||||
params.userdata = userdata;
|
||||
params.version = 0;
|
||||
params.version_min = 0;
|
||||
|
||||
return vchiq_open_service_params(instance, ¶ms, pservice);
|
||||
}
|
||||
|
||||
VCHIQ_STATUS_T
|
||||
vchiq_add_service_params(VCHIQ_INSTANCE_T instance,
|
||||
const VCHIQ_SERVICE_PARAMS_T *params,
|
||||
VCHIQ_SERVICE_HANDLE_T *pservice)
|
||||
VCHIQ_SERVICE_HANDLE_T *phandle)
|
||||
{
|
||||
VCHIQ_STATUS_T status;
|
||||
|
||||
@@ -286,17 +275,17 @@ vchiq_add_service_params(VCHIQ_INSTANCE_T instance,
|
||||
params,
|
||||
NULL/*vchi_callback*/,
|
||||
0/*!open*/,
|
||||
pservice);
|
||||
phandle);
|
||||
|
||||
vcos_log_trace( "%s returning service handle = 0x%08x", __func__, (uint32_t)*pservice );
|
||||
vcos_log_trace( "%s returning service handle = 0x%08x", __func__, (uint32_t)*phandle );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
VCHIQ_STATUS_T
|
||||
vchiq_open_service_params(VCHIQ_INSTANCE_T instance,
|
||||
vchiq_open_service(VCHIQ_INSTANCE_T instance,
|
||||
const VCHIQ_SERVICE_PARAMS_T *params,
|
||||
VCHIQ_SERVICE_HANDLE_T *pservice)
|
||||
VCHIQ_SERVICE_HANDLE_T *phandle)
|
||||
{
|
||||
VCHIQ_STATUS_T status;
|
||||
|
||||
@@ -318,9 +307,9 @@ vchiq_open_service_params(VCHIQ_INSTANCE_T instance,
|
||||
params,
|
||||
NULL/*vchi_callback*/,
|
||||
1/*open*/,
|
||||
pservice);
|
||||
phandle);
|
||||
|
||||
vcos_log_trace( "%s returning service handle = 0x%08x", __func__, (uint32_t)*pservice );
|
||||
vcos_log_trace( "%s returning service handle = 0x%08x", __func__, (uint32_t)*phandle );
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -328,40 +317,43 @@ vchiq_open_service_params(VCHIQ_INSTANCE_T instance,
|
||||
VCHIQ_STATUS_T
|
||||
vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle)
|
||||
{
|
||||
VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
|
||||
VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
|
||||
int ret;
|
||||
|
||||
vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
RETRY(ret,ioctl(service->fd, VCHIQ_IOC_CLOSE_SERVICE, service->handle));
|
||||
|
||||
if (service->is_client)
|
||||
service->lib_handle = VCHIQ_SERVICE_HANDLE_INVALID;
|
||||
|
||||
if (ret != 0)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
service->handle = VCHIQ_INVALID_HANDLE;
|
||||
return VCHIQ_SUCCESS;
|
||||
}
|
||||
|
||||
VCHIQ_STATUS_T
|
||||
vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T handle)
|
||||
{
|
||||
VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
|
||||
VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
|
||||
int ret;
|
||||
|
||||
vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
RETRY(ret,ioctl(service->fd, VCHIQ_IOC_REMOVE_SERVICE, service->handle));
|
||||
|
||||
service->lib_handle = VCHIQ_SERVICE_HANDLE_INVALID;
|
||||
|
||||
if (ret != 0)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
service->handle = VCHIQ_INVALID_HANDLE;
|
||||
return VCHIQ_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -370,13 +362,13 @@ vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle,
|
||||
const VCHIQ_ELEMENT_T *elements,
|
||||
int count)
|
||||
{
|
||||
VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
|
||||
VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
|
||||
VCHIQ_QUEUE_MESSAGE_T args;
|
||||
int ret;
|
||||
|
||||
vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
args.handle = service->handle;
|
||||
@@ -402,13 +394,13 @@ vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
|
||||
int size,
|
||||
void *userdata)
|
||||
{
|
||||
VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
|
||||
VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
|
||||
VCHIQ_QUEUE_BULK_TRANSFER_T args;
|
||||
int ret;
|
||||
|
||||
vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
args.handle = service->handle;
|
||||
@@ -427,13 +419,13 @@ vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle,
|
||||
int size,
|
||||
void *userdata)
|
||||
{
|
||||
VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
|
||||
VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
|
||||
VCHIQ_QUEUE_BULK_TRANSFER_T args;
|
||||
int ret;
|
||||
|
||||
vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
args.handle = service->handle;
|
||||
@@ -481,13 +473,13 @@ vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
|
||||
void *userdata,
|
||||
VCHIQ_BULK_MODE_T mode)
|
||||
{
|
||||
VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
|
||||
VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
|
||||
VCHIQ_QUEUE_BULK_TRANSFER_T args;
|
||||
int ret;
|
||||
|
||||
vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
args.handle = service->handle;
|
||||
@@ -507,13 +499,13 @@ vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle,
|
||||
void *userdata,
|
||||
VCHIQ_BULK_MODE_T mode)
|
||||
{
|
||||
VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
|
||||
VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
|
||||
VCHIQ_QUEUE_BULK_TRANSFER_T args;
|
||||
int ret;
|
||||
|
||||
vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
args.handle = service->handle;
|
||||
@@ -555,14 +547,30 @@ vchiq_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T handle,
|
||||
int
|
||||
vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T handle)
|
||||
{
|
||||
VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
|
||||
VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
return ioctl(service->fd, VCHIQ_IOC_GET_CLIENT_ID, service->handle);
|
||||
}
|
||||
|
||||
void *
|
||||
vchiq_get_service_userdata(VCHIQ_SERVICE_HANDLE_T handle)
|
||||
{
|
||||
VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
|
||||
|
||||
return service ? service->base.userdata : NULL;
|
||||
}
|
||||
|
||||
int
|
||||
vchiq_get_service_fourcc(VCHIQ_SERVICE_HANDLE_T handle)
|
||||
{
|
||||
VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
|
||||
|
||||
return service ? service->base.fourcc : 0;
|
||||
}
|
||||
|
||||
VCHIQ_STATUS_T
|
||||
vchiq_get_config(VCHIQ_INSTANCE_T instance,
|
||||
int config_size,
|
||||
@@ -585,10 +593,10 @@ vchiq_get_config(VCHIQ_INSTANCE_T instance,
|
||||
int32_t
|
||||
vchiq_use_service( const VCHIQ_SERVICE_HANDLE_T handle )
|
||||
{
|
||||
VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
|
||||
VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
|
||||
int ret;
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
RETRY(ret,ioctl(service->fd, VCHIQ_IOC_USE_SERVICE, service->handle));
|
||||
@@ -598,10 +606,14 @@ vchiq_use_service( const VCHIQ_SERVICE_HANDLE_T handle )
|
||||
int32_t
|
||||
vchiq_release_service( const VCHIQ_SERVICE_HANDLE_T handle )
|
||||
{
|
||||
VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
|
||||
int ret;
|
||||
RETRY(ret,ioctl(service->fd, VCHIQ_IOC_RELEASE_SERVICE, service->handle));
|
||||
return ret;
|
||||
VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
|
||||
int ret;
|
||||
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
RETRY(ret,ioctl(service->fd, VCHIQ_IOC_RELEASE_SERVICE, service->handle));
|
||||
return ret;
|
||||
}
|
||||
|
||||
VCHIQ_STATUS_T
|
||||
@@ -609,10 +621,10 @@ vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T handle,
|
||||
VCHIQ_SERVICE_OPTION_T option, int value)
|
||||
{
|
||||
VCHIQ_SET_SERVICE_OPTION_T args;
|
||||
VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
|
||||
VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
|
||||
int ret;
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
args.handle = service->handle;
|
||||
@@ -676,10 +688,10 @@ vchi_msg_peek( VCHI_SERVICE_HANDLE_T handle,
|
||||
uint32_t *msg_size,
|
||||
VCHI_FLAGS_T flags )
|
||||
{
|
||||
VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
|
||||
VCHI_SERVICE_T *service = find_service_by_handle(handle);
|
||||
int ret;
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
ret = fill_peek_buf(service, flags);
|
||||
@@ -706,9 +718,9 @@ vchi_msg_peek( VCHI_SERVICE_HANDLE_T handle,
|
||||
int32_t
|
||||
vchi_msg_remove( VCHI_SERVICE_HANDLE_T handle )
|
||||
{
|
||||
VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
|
||||
VCHI_SERVICE_T *service = find_service_by_handle(handle);
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
/* Why would you call vchi_msg_remove without calling vchi_msg_peek first? */
|
||||
@@ -741,7 +753,7 @@ vchi_msg_queue( VCHI_SERVICE_HANDLE_T handle,
|
||||
VCHI_FLAGS_T flags,
|
||||
void * msg_handle )
|
||||
{
|
||||
VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
|
||||
VCHI_SERVICE_T *service = find_service_by_handle(handle);
|
||||
VCHIQ_QUEUE_MESSAGE_T args;
|
||||
VCHIQ_ELEMENT_T element = {data, data_size};
|
||||
int ret;
|
||||
@@ -749,7 +761,7 @@ vchi_msg_queue( VCHI_SERVICE_HANDLE_T handle,
|
||||
vcos_unused(msg_handle);
|
||||
vcos_assert(flags == VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
args.handle = service->handle;
|
||||
@@ -781,11 +793,11 @@ vchi_bulk_queue_receive( VCHI_SERVICE_HANDLE_T handle,
|
||||
VCHI_FLAGS_T flags,
|
||||
void * bulk_handle )
|
||||
{
|
||||
VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
|
||||
VCHI_SERVICE_T *service = find_service_by_handle(handle);
|
||||
VCHIQ_QUEUE_BULK_TRANSFER_T args;
|
||||
int ret;
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
switch ((int)flags) {
|
||||
@@ -834,11 +846,11 @@ vchi_bulk_queue_transmit( VCHI_SERVICE_HANDLE_T handle,
|
||||
VCHI_FLAGS_T flags,
|
||||
void * bulk_handle )
|
||||
{
|
||||
VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
|
||||
VCHI_SERVICE_T *service = find_service_by_handle(handle);
|
||||
VCHIQ_QUEUE_BULK_TRANSFER_T args;
|
||||
int ret;
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
switch ((int)flags) {
|
||||
@@ -888,13 +900,13 @@ vchi_msg_dequeue( VCHI_SERVICE_HANDLE_T handle,
|
||||
uint32_t *actual_msg_size,
|
||||
VCHI_FLAGS_T flags )
|
||||
{
|
||||
VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
|
||||
VCHI_SERVICE_T *service = find_service_by_handle(handle);
|
||||
VCHIQ_DEQUEUE_MESSAGE_T args;
|
||||
int ret;
|
||||
|
||||
vcos_assert(flags == VCHI_FLAGS_NONE || flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
if (service->peek_size >= 0)
|
||||
@@ -959,7 +971,7 @@ vchi_msg_queuev( VCHI_SERVICE_HANDLE_T handle,
|
||||
VCHI_FLAGS_T flags,
|
||||
void *msg_handle )
|
||||
{
|
||||
VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
|
||||
VCHI_SERVICE_T *service = find_service_by_handle(handle);
|
||||
VCHIQ_QUEUE_MESSAGE_T args;
|
||||
int ret;
|
||||
|
||||
@@ -967,7 +979,7 @@ vchi_msg_queuev( VCHI_SERVICE_HANDLE_T handle,
|
||||
|
||||
vcos_assert(flags == VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
args.handle = service->handle;
|
||||
@@ -1025,10 +1037,10 @@ vchi_msg_hold( VCHI_SERVICE_HANDLE_T handle,
|
||||
VCHI_FLAGS_T flags,
|
||||
VCHI_HELD_MSG_T *message_handle )
|
||||
{
|
||||
VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
|
||||
VCHI_SERVICE_T *service = find_service_by_handle(handle);
|
||||
int ret;
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
ret = fill_peek_buf(service, flags);
|
||||
@@ -1151,6 +1163,8 @@ vchi_service_open( VCHI_INSTANCE_T instance_handle,
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.fourcc = setup->service_id;
|
||||
params.userdata = setup->callback_param;
|
||||
params.version = setup->version.version;
|
||||
params.version_min = setup->version.version_min;
|
||||
|
||||
status = create_service((VCHIQ_INSTANCE_T)instance_handle,
|
||||
¶ms,
|
||||
@@ -1171,6 +1185,8 @@ vchi_service_create( VCHI_INSTANCE_T instance_handle,
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.fourcc = setup->service_id;
|
||||
params.userdata = setup->callback_param;
|
||||
params.version = setup->version.version;
|
||||
params.version_min = setup->version.version_min;
|
||||
|
||||
status = create_service((VCHIQ_INSTANCE_T)instance_handle,
|
||||
¶ms,
|
||||
@@ -1184,16 +1200,16 @@ vchi_service_create( VCHI_INSTANCE_T instance_handle,
|
||||
int32_t
|
||||
vchi_service_close( const VCHI_SERVICE_HANDLE_T handle )
|
||||
{
|
||||
VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
|
||||
VCHI_SERVICE_T *service = find_service_by_handle(handle);
|
||||
int ret;
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
RETRY(ret,ioctl(service->fd, VCHIQ_IOC_REMOVE_SERVICE, service->handle));
|
||||
RETRY(ret,ioctl(service->fd, VCHIQ_IOC_CLOSE_SERVICE, service->handle));
|
||||
|
||||
if (ret == 0)
|
||||
service->handle = VCHIQ_INVALID_HANDLE;
|
||||
if (service->is_client)
|
||||
service->lib_handle = VCHIQ_SERVICE_HANDLE_INVALID;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1201,16 +1217,15 @@ vchi_service_close( const VCHI_SERVICE_HANDLE_T handle )
|
||||
int32_t
|
||||
vchi_service_destroy( const VCHI_SERVICE_HANDLE_T handle )
|
||||
{
|
||||
VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
|
||||
VCHI_SERVICE_T *service = find_service_by_handle(handle);
|
||||
int ret;
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
RETRY(ret,ioctl(service->fd, VCHIQ_IOC_REMOVE_SERVICE, service->handle));
|
||||
|
||||
if (ret == 0)
|
||||
service->handle = VCHIQ_INVALID_HANDLE;
|
||||
service->lib_handle = VCHIQ_SERVICE_HANDLE_INVALID;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1276,10 +1291,10 @@ vchi_writebuf_uint16( void *_ptr, uint16_t value )
|
||||
int32_t
|
||||
vchi_service_use( const VCHI_SERVICE_HANDLE_T handle )
|
||||
{
|
||||
VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
|
||||
VCHI_SERVICE_T *service = find_service_by_handle(handle);
|
||||
int ret;
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
RETRY(ret,ioctl(service->fd, VCHIQ_IOC_USE_SERVICE, service->handle));
|
||||
@@ -1298,10 +1313,10 @@ vchi_service_use( const VCHI_SERVICE_HANDLE_T handle )
|
||||
***********************************************************/
|
||||
int32_t vchi_service_release( const VCHI_SERVICE_HANDLE_T handle )
|
||||
{
|
||||
VCHI_SERVICE_T *service = (VCHI_SERVICE_T *)handle;
|
||||
VCHI_SERVICE_T *service = find_service_by_handle(handle);
|
||||
int ret;
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
RETRY(ret,ioctl(service->fd, VCHIQ_IOC_RELEASE_SERVICE, service->handle));
|
||||
@@ -1329,7 +1344,7 @@ VCHIQ_STATUS_T vchiq_dump_phys_mem( VCHIQ_SERVICE_HANDLE_T handle,
|
||||
VCHIQ_DUMP_MEM_T dump_mem;
|
||||
int ret;
|
||||
|
||||
if (!is_valid_service(service))
|
||||
if (!service)
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
dump_mem.virt_addr = ptr;
|
||||
@@ -1471,7 +1486,7 @@ completion_thread(void *arg)
|
||||
completion->reason, (uint32_t)completion->header,
|
||||
(uint32_t)&service->base, (uint32_t)completion->bulk_userdata );
|
||||
service->base.callback(completion->reason, completion->header,
|
||||
&service->base, completion->bulk_userdata);
|
||||
service->lib_handle, completion->bulk_userdata);
|
||||
}
|
||||
else if (service->vchi_callback)
|
||||
{
|
||||
@@ -1481,6 +1496,13 @@ completion_thread(void *arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (args.msgbufcount)
|
||||
{
|
||||
void *msgbuf = msgbufs[--args.msgbufcount];
|
||||
free_msgbuf(msgbuf);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1489,7 +1511,7 @@ create_service(VCHIQ_INSTANCE_T instance,
|
||||
const VCHIQ_SERVICE_PARAMS_T *params,
|
||||
VCHI_CALLBACK_T vchi_callback,
|
||||
int is_open,
|
||||
VCHIQ_SERVICE_HANDLE_T *pservice)
|
||||
VCHIQ_SERVICE_HANDLE_T *phandle)
|
||||
{
|
||||
VCHIQ_SERVICE_T *service = NULL;
|
||||
VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
|
||||
@@ -1506,7 +1528,7 @@ create_service(VCHIQ_INSTANCE_T instance,
|
||||
/* Find a free service */
|
||||
for (i = 0; i < instance->used_services; i++)
|
||||
{
|
||||
if (instance->services[i].handle == VCHIQ_INVALID_HANDLE)
|
||||
if (instance->services[i].lib_handle == VCHIQ_SERVICE_HANDLE_INVALID)
|
||||
{
|
||||
service = &instance->services[i];
|
||||
break;
|
||||
@@ -1518,7 +1540,7 @@ create_service(VCHIQ_INSTANCE_T instance,
|
||||
for (i = (instance->used_services - 1); i >= 0; i--)
|
||||
{
|
||||
VCHIQ_SERVICE_T *srv = &instance->services[i];
|
||||
if (srv->handle == VCHIQ_INVALID_HANDLE)
|
||||
if (srv->lib_handle == VCHIQ_SERVICE_HANDLE_INVALID)
|
||||
{
|
||||
service = srv;
|
||||
}
|
||||
@@ -1535,14 +1557,29 @@ create_service(VCHIQ_INSTANCE_T instance,
|
||||
}
|
||||
}
|
||||
|
||||
if (!service && (status == VCHIQ_SUCCESS) &&
|
||||
(instance->used_services < VCHIQ_MAX_INSTANCE_SERVICES))
|
||||
service = &instance->services[instance->used_services++];
|
||||
if (!service && (status == VCHIQ_SUCCESS))
|
||||
{
|
||||
if (instance->used_services < VCHIQ_MAX_INSTANCE_SERVICES)
|
||||
service = &instance->services[instance->used_services++];
|
||||
else
|
||||
status = VCHIQ_ERROR;
|
||||
}
|
||||
|
||||
if (service)
|
||||
{
|
||||
if (!handle_seq)
|
||||
handle_seq = VCHIQ_MAX_INSTANCE_SERVICES;
|
||||
service->lib_handle = handle_seq | (service - instance->services);
|
||||
handle_seq += VCHIQ_MAX_INSTANCE_SERVICES;
|
||||
}
|
||||
|
||||
vcos_mutex_unlock(&instance->mutex);
|
||||
|
||||
if (service)
|
||||
{
|
||||
VCHIQ_CREATE_SERVICE_T args;
|
||||
int ret;
|
||||
|
||||
service->base.fourcc = params->fourcc;
|
||||
service->base.callback = params->callback;
|
||||
service->vchi_callback = vchi_callback;
|
||||
@@ -1550,12 +1587,13 @@ create_service(VCHIQ_INSTANCE_T instance,
|
||||
service->fd = instance->fd;
|
||||
service->peek_size = -1;
|
||||
service->peek_buf = NULL;
|
||||
service->is_client = is_open;
|
||||
|
||||
args.params = *params;
|
||||
args.params.userdata = service;
|
||||
args.is_open = is_open;
|
||||
args.is_vchi = (params->callback == NULL);
|
||||
args.handle = -1; /* OUT parameter */
|
||||
args.handle = VCHIQ_SERVICE_HANDLE_INVALID; /* OUT parameter */
|
||||
RETRY(ret, ioctl(instance->fd, VCHIQ_IOC_CREATE_SERVICE, &args));
|
||||
if (ret == 0)
|
||||
service->handle = args.handle;
|
||||
@@ -1563,9 +1601,20 @@ create_service(VCHIQ_INSTANCE_T instance,
|
||||
status = VCHIQ_ERROR;
|
||||
}
|
||||
|
||||
*pservice = (status == VCHIQ_SUCCESS) ? &service->base : NULL;
|
||||
if (status == VCHIQ_SUCCESS)
|
||||
{
|
||||
*phandle = service->lib_handle;
|
||||
}
|
||||
else
|
||||
{
|
||||
vcos_mutex_lock(&instance->mutex);
|
||||
|
||||
vcos_mutex_unlock(&instance->mutex);
|
||||
service->lib_handle = VCHIQ_SERVICE_HANDLE_INVALID;
|
||||
|
||||
vcos_mutex_unlock(&instance->mutex);
|
||||
|
||||
*phandle = VCHIQ_SERVICE_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define PAGE_SIZE 4096
|
||||
#endif
|
||||
|
||||
#define INIT_PARAMS(sp_, fourcc_, cb_, userdata_, ver_) \
|
||||
do { \
|
||||
memset((sp_), 0, sizeof(*(sp_))); \
|
||||
(sp_)->fourcc = fourcc_; \
|
||||
(sp_)->callback = cb_; \
|
||||
(sp_)->userdata = userdata_; \
|
||||
(sp_)->version = ver_; \
|
||||
(sp_)->version_min = ver_; \
|
||||
} while (0)
|
||||
|
||||
|
||||
static struct test_params g_params = { MSG_CONFIG, 64, 100, 1, 1, 1, 0, 0, 0, 0 };
|
||||
static const char *g_servname = "echo";
|
||||
|
||||
@@ -79,6 +90,7 @@ static VCHIQ_STATUS_T vchiq_bulk_test(void);
|
||||
static VCHIQ_STATUS_T vchiq_ctrl_test(void);
|
||||
static VCHIQ_STATUS_T vchiq_functional_test(void);
|
||||
static VCHIQ_STATUS_T vchiq_ping_test(void);
|
||||
static VCHIQ_STATUS_T vchiq_signal_test(void);
|
||||
|
||||
static VCHIQ_STATUS_T do_functional_test(void);
|
||||
static void do_ping_test(VCHIQ_SERVICE_HANDLE_T service, int size, int async, int oneway, int iters);
|
||||
@@ -105,6 +117,42 @@ static void usage(void);
|
||||
static void check_timer(void);
|
||||
static char *buf_align(char *buf, int align_size, int align);
|
||||
|
||||
#ifdef ANDROID
|
||||
|
||||
static int g_timeout_ms = 0;
|
||||
static pid_t main_process_pid;
|
||||
static void kill_timeout_handler(int cause, siginfo_t *how, void *ucontext);
|
||||
static int setup_auto_kill(int timeout_ms);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include <fcntl.h>
|
||||
#include "interface/vmcs_host/vc_cma.h"
|
||||
|
||||
static void reserve_test(int reserve, int delay)
|
||||
{
|
||||
int fd = open("/dev/vc-cma", O_RDWR);
|
||||
int rc = -1;
|
||||
if (fd >= 0)
|
||||
{
|
||||
rc = ioctl(fd, VC_CMA_IOC_RESERVE, reserve);
|
||||
if (rc == 0)
|
||||
{
|
||||
printf("Sleeping for %d seconds...\n", delay);
|
||||
sleep(delay);
|
||||
}
|
||||
else
|
||||
printf("* failed to ioctl /dev/vc-cma - rc %d\n", rc);
|
||||
close(fd);
|
||||
}
|
||||
else
|
||||
printf("* failed to open /dev/vc-cma - rc %d\n", fd);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int vchiq_test(int argc, char **argv)
|
||||
{
|
||||
VCHIQ_STATUS_T status;
|
||||
@@ -112,6 +160,7 @@ static int vchiq_test(int argc, char **argv)
|
||||
int run_ctrl_test = 0;
|
||||
int run_functional_test = 0;
|
||||
int run_ping_test = 0;
|
||||
int run_signal_test = 0;
|
||||
int verbose = 0;
|
||||
int argn;
|
||||
|
||||
@@ -155,6 +204,10 @@ static int vchiq_test(int argc, char **argv)
|
||||
{
|
||||
usage();
|
||||
}
|
||||
else if (strcmp(arg, "-i") == 0)
|
||||
{
|
||||
run_signal_test = 1;
|
||||
}
|
||||
else if (strcmp(arg, "-m") == 0)
|
||||
{
|
||||
g_params.client_message_quota = atoi(argv[argn++]);
|
||||
@@ -170,8 +223,39 @@ static int vchiq_test(int argc, char **argv)
|
||||
}
|
||||
else if (strcmp(arg, "-q") == 0)
|
||||
{
|
||||
/* coverity[missing_lock : FALSE] - g_server_reply is not used for mutual exclusion */
|
||||
g_params.verify = 0;
|
||||
}
|
||||
#ifdef __linux__
|
||||
else if (strcmp(arg, "-r") == 0)
|
||||
{
|
||||
int reserve, delay;
|
||||
if (argn+1 < argc)
|
||||
{
|
||||
reserve = atoi(argv[argn++]);
|
||||
delay = atoi(argv[argn++]);
|
||||
reserve_test(reserve, delay);
|
||||
exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("not enough arguments (-r reserve delay)\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef ANDROID
|
||||
else if (strcmp(arg, "-K") == 0)
|
||||
{
|
||||
if (argn < argc)
|
||||
g_timeout_ms = atoi(argv[argn++]);
|
||||
else
|
||||
{
|
||||
printf("not enough arguments (-K timeout)\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (strcmp(arg, "-t") == 0)
|
||||
{
|
||||
check_timer();
|
||||
@@ -196,7 +280,7 @@ static int vchiq_test(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if ((run_ctrl_test + run_bulk_test + run_functional_test + run_ping_test) != 1)
|
||||
if ((run_ctrl_test + run_bulk_test + run_functional_test + run_ping_test + run_signal_test) != 1)
|
||||
usage();
|
||||
|
||||
if (argn < argc)
|
||||
@@ -241,6 +325,8 @@ static int vchiq_test(int argc, char **argv)
|
||||
status = vchiq_functional_test();
|
||||
else if (run_ping_test)
|
||||
status = vchiq_ping_test();
|
||||
else if (run_signal_test)
|
||||
status = vchiq_signal_test();
|
||||
|
||||
return (status == VCHIQ_SUCCESS) ? 0 : -1;
|
||||
}
|
||||
@@ -285,7 +371,12 @@ vchiq_bulk_test(void)
|
||||
memset(bulk_rx_data[i], 0xff, g_params.blocksize);
|
||||
}
|
||||
|
||||
// fprintf(stderr, "vchiq_test: opening vchiq\n");
|
||||
#ifdef ANDROID
|
||||
if (g_timeout_ms)
|
||||
{
|
||||
setup_auto_kill(g_timeout_ms);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (vchiq_initialise(&vchiq_instance) != VCHIQ_SUCCESS)
|
||||
{
|
||||
@@ -297,13 +388,12 @@ vchiq_bulk_test(void)
|
||||
|
||||
memset(&service_params, 0, sizeof(service_params));
|
||||
|
||||
service_params.version = service_params.version_min = VCHIQ_TEST_VER;
|
||||
service_params.fourcc = VCHIQ_MAKE_FOURCC(g_servname[0], g_servname[1], g_servname[2], g_servname[3]);
|
||||
service_params.callback = clnt_callback;
|
||||
service_params.userdata = "clnt userdata";
|
||||
service_params.version = 0;
|
||||
service_params.version_min = 0;
|
||||
|
||||
if (vchiq_open_service_params(vchiq_instance, &service_params, &vchiq_service) != VCHIQ_SUCCESS)
|
||||
if (vchiq_open_service(vchiq_instance, &service_params, &vchiq_service) != VCHIQ_SUCCESS)
|
||||
{
|
||||
printf("* failed to open service - already in use?\n");
|
||||
return VCHIQ_ERROR;
|
||||
@@ -311,12 +401,13 @@ vchiq_bulk_test(void)
|
||||
|
||||
printf("Bulk test - service:%s, block size:%d, iters:%d\n", g_servname, g_params.blocksize, g_params.iters);
|
||||
|
||||
/* coverity[missing_lock : FALSE] - g_server_reply is not used for mutual exclusion */
|
||||
g_params.echo = want_echo;
|
||||
element = elements;
|
||||
element->data = &g_params;
|
||||
element->size = sizeof(g_params);
|
||||
element++;
|
||||
|
||||
|
||||
vchiq_queue_message(vchiq_service, elements, element - elements);
|
||||
|
||||
vcos_event_wait(&g_server_reply);
|
||||
@@ -405,6 +496,13 @@ vchiq_ctrl_test(void)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
if (g_timeout_ms)
|
||||
{
|
||||
setup_auto_kill(g_timeout_ms);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (vchiq_initialise(&vchiq_instance) != VCHIQ_SUCCESS)
|
||||
{
|
||||
printf("* failed to open vchiq instance\n");
|
||||
@@ -418,10 +516,10 @@ vchiq_ctrl_test(void)
|
||||
service_params.fourcc = VCHIQ_MAKE_FOURCC(g_servname[0], g_servname[1], g_servname[2], g_servname[3]);
|
||||
service_params.callback = clnt_callback;
|
||||
service_params.userdata = "clnt userdata";
|
||||
service_params.version = 0;
|
||||
service_params.version_min = 0;
|
||||
service_params.version = VCHIQ_TEST_VER;
|
||||
service_params.version_min = VCHIQ_TEST_VER;
|
||||
|
||||
if (vchiq_open_service_params(vchiq_instance, &service_params, &vchiq_service) != VCHIQ_SUCCESS)
|
||||
if (vchiq_open_service(vchiq_instance, &service_params, &vchiq_service) != VCHIQ_SUCCESS)
|
||||
{
|
||||
printf("* failed to open service - already in use?\n");
|
||||
return VCHIQ_ERROR;
|
||||
@@ -505,6 +603,7 @@ vchiq_ping_test(void)
|
||||
VCHIQ_SERVICE_HANDLE_T vchiq_service;
|
||||
VCHI_SERVICE_HANDLE_T vchi_service;
|
||||
SERVICE_CREATION_T service_params;
|
||||
VCHIQ_SERVICE_PARAMS_T vchiq_service_params;
|
||||
int fourcc;
|
||||
|
||||
static int sizes[] = { 0, 1024, 2048, VCHIQ_MAX_MSG_SIZE };
|
||||
@@ -512,7 +611,14 @@ vchiq_ping_test(void)
|
||||
|
||||
fourcc = VCHIQ_MAKE_FOURCC(g_servname[0], g_servname[1], g_servname[2], g_servname[3]);
|
||||
|
||||
printf("Ping test - service:%s, iters:%d\n", g_servname, g_params.iters);
|
||||
printf("Ping test - service:%s, iters:%d, version %d\n", g_servname, g_params.iters, VCHIQ_TEST_VER);
|
||||
|
||||
#ifdef ANDROID
|
||||
if (g_timeout_ms)
|
||||
{
|
||||
setup_auto_kill(g_timeout_ms);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (vchiq_initialise(&vchiq_instance) != VCHIQ_SUCCESS)
|
||||
{
|
||||
@@ -522,6 +628,8 @@ vchiq_ping_test(void)
|
||||
|
||||
vchiq_connect(vchiq_instance);
|
||||
|
||||
memset(&service_params, 0, sizeof(service_params));
|
||||
service_params.version.version = service_params.version.version_min = VCHIQ_TEST_VER;
|
||||
service_params.service_id = fourcc;
|
||||
service_params.callback = vchi_clnt_callback;
|
||||
service_params.callback_param = &vchi_service;
|
||||
@@ -560,7 +668,8 @@ vchiq_ping_test(void)
|
||||
|
||||
vchi_service_close(vchi_service);
|
||||
|
||||
if (vchiq_open_service(vchiq_instance, fourcc, clnt_callback, "clnt userdata", &vchiq_service) != VCHIQ_SUCCESS)
|
||||
INIT_PARAMS(&vchiq_service_params, fourcc, clnt_callback, "clnt userdata", VCHIQ_TEST_VER);
|
||||
if (vchiq_open_service(vchiq_instance, &vchiq_service_params, &vchiq_service) != VCHIQ_SUCCESS)
|
||||
{
|
||||
printf("* failed to open service - already in use?\n");
|
||||
return VCHIQ_ERROR;
|
||||
@@ -592,7 +701,52 @@ vchiq_ping_test(void)
|
||||
do_ping_test(vchiq_service, sizes[i], 1000, 1000, iter_count/50);
|
||||
}
|
||||
|
||||
vchiq_remove_service(vchiq_service);
|
||||
vchiq_close_service(vchiq_service);
|
||||
|
||||
return VCHIQ_SUCCESS;
|
||||
}
|
||||
|
||||
static VCHIQ_STATUS_T
|
||||
vchiq_signal_test(void)
|
||||
{
|
||||
/* Measure message round trip time for various sizes*/
|
||||
VCHIQ_INSTANCE_T vchiq_instance;
|
||||
VCHIQ_SERVICE_HANDLE_T vchiq_service;
|
||||
VCHIQ_SERVICE_PARAMS_T vchiq_service_params;
|
||||
int fourcc;
|
||||
|
||||
static int sizes[] = { 0, 1024, 2048, VCHIQ_MAX_MSG_SIZE };
|
||||
unsigned int i;
|
||||
|
||||
fourcc = VCHIQ_MAKE_FOURCC(g_servname[0], g_servname[1], g_servname[2], g_servname[3]);
|
||||
|
||||
printf("signal test - service:%s, iters:%d, version %d\n", g_servname, g_params.iters, VCHIQ_TEST_VER);
|
||||
|
||||
#ifdef ANDROID
|
||||
if (g_timeout_ms)
|
||||
{
|
||||
setup_auto_kill(g_timeout_ms);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (vchiq_initialise(&vchiq_instance) != VCHIQ_SUCCESS)
|
||||
{
|
||||
printf("* failed to open vchiq instance\n");
|
||||
return VCHIQ_ERROR;
|
||||
}
|
||||
|
||||
vchiq_connect(vchiq_instance);
|
||||
|
||||
INIT_PARAMS(&vchiq_service_params, fourcc, clnt_callback, "clnt userdata", VCHIQ_TEST_VER);
|
||||
if (vchiq_open_service(vchiq_instance, &vchiq_service_params, &vchiq_service) != VCHIQ_SUCCESS)
|
||||
{
|
||||
printf("* failed to open service - already in use?\n");
|
||||
return VCHIQ_ERROR;
|
||||
}
|
||||
|
||||
vchiq_bulk_transmit(vchiq_service, &sizes, 16, 0, VCHIQ_BULK_MODE_BLOCKING);
|
||||
|
||||
vchiq_close_service(vchiq_service);
|
||||
|
||||
return VCHIQ_SUCCESS;
|
||||
}
|
||||
@@ -609,6 +763,13 @@ do_functional_test(void)
|
||||
|
||||
vcos_event_create(&func_test_sync, "test_sync");
|
||||
|
||||
#ifdef ANDROID
|
||||
if (g_timeout_ms)
|
||||
{
|
||||
setup_auto_kill(g_timeout_ms);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (func_data_test_start != -1)
|
||||
goto bulk_tests_only;
|
||||
|
||||
@@ -617,9 +778,16 @@ do_functional_test(void)
|
||||
EXPECT(vchiq_get_config(instance, sizeof(config) + 1, &config), VCHIQ_ERROR); // too large
|
||||
EXPECT(vchiq_get_config(instance, sizeof(config), &config), VCHIQ_SUCCESS); // just right
|
||||
EXPECT(config.max_msg_size, VCHIQ_MAX_MSG_SIZE);
|
||||
EXPECT(vchiq_add_service(instance, FUNC_FOURCC, func_clnt_callback, (void *)1, &service), VCHIQ_SUCCESS);
|
||||
EXPECT(vchiq_add_service(instance, FUNC_FOURCC, func_clnt_callback, (void *)2, &service2), VCHIQ_SUCCESS);
|
||||
EXPECT(vchiq_add_service(instance, FUNC_FOURCC, clnt_callback, (void *)3, &service3), VCHIQ_ERROR); // callback doesn't match
|
||||
|
||||
INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, (void *)1, VCHIQ_TEST_VER);
|
||||
EXPECT(vchiq_add_service(instance, &service_params, &service), VCHIQ_SUCCESS);
|
||||
|
||||
INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, (void *)2, VCHIQ_TEST_VER);
|
||||
EXPECT(vchiq_add_service(instance, &service_params, &service2), VCHIQ_SUCCESS);
|
||||
|
||||
INIT_PARAMS(&service_params, FUNC_FOURCC, clnt_callback, (void *)3, VCHIQ_TEST_VER);
|
||||
EXPECT(vchiq_add_service(instance, &service_params, &service3), VCHIQ_ERROR); // callback doesn't match
|
||||
|
||||
EXPECT(vchiq_set_service_option(service, VCHIQ_SERVICE_OPTION_AUTOCLOSE, 0), VCHIQ_SUCCESS);
|
||||
EXPECT(vchiq_set_service_option(service, VCHIQ_SERVICE_OPTION_AUTOCLOSE, 1), VCHIQ_SUCCESS);
|
||||
EXPECT(vchiq_set_service_option(service, 42, 1), VCHIQ_ERROR); // invalid option
|
||||
@@ -628,33 +796,43 @@ do_functional_test(void)
|
||||
EXPECT(vchiq_remove_service(service2), VCHIQ_SUCCESS);
|
||||
EXPECT(vchiq_queue_message(service, NULL, 0), VCHIQ_ERROR); // service not valid
|
||||
EXPECT(vchiq_set_service_option(service, VCHIQ_SERVICE_OPTION_AUTOCLOSE, 0), VCHIQ_ERROR); // service not valid
|
||||
EXPECT(vchiq_add_service(instance, FUNC_FOURCC, clnt_callback, (void *)3, &service3), VCHIQ_SUCCESS);
|
||||
|
||||
INIT_PARAMS(&service_params, FUNC_FOURCC, clnt_callback, (void *)3, VCHIQ_TEST_VER);
|
||||
EXPECT(vchiq_add_service(instance, &service_params, &service3), VCHIQ_SUCCESS);
|
||||
|
||||
EXPECT(vchiq_queue_message(service, NULL, 0), VCHIQ_ERROR); // service not open
|
||||
EXPECT(vchiq_queue_bulk_transmit(service, clnt_service1_data, sizeof(clnt_service1_data), (void *)1), VCHIQ_ERROR); // service not open
|
||||
EXPECT(vchiq_queue_bulk_receive(service2, clnt_service2_data, sizeof(clnt_service2_data), (void *)2), VCHIQ_ERROR); // service not open
|
||||
EXPECT(vchiq_queue_bulk_receive(service, 0, sizeof(clnt_service1_data), (void *)1), VCHIQ_ERROR); // invalid buffer
|
||||
EXPECT(vchiq_shutdown(instance), VCHIQ_SUCCESS);
|
||||
EXPECT(vchiq_initialise(&instance), VCHIQ_SUCCESS);
|
||||
EXPECT(vchiq_open_service(instance, FUNC_FOURCC, func_clnt_callback, (void*)1, &service), VCHIQ_ERROR); // not connected
|
||||
INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, (void*)1, 0);
|
||||
EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_ERROR); // not connected
|
||||
EXPECT(vchiq_connect(instance), VCHIQ_SUCCESS);
|
||||
EXPECT(vchiq_open_service(instance, FUNC_FOURCC, func_clnt_callback, (void*)1, &service), VCHIQ_ERROR); // wrong version number
|
||||
EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_ERROR); // wrong version number
|
||||
memset(&service_params, 0, sizeof(service_params));
|
||||
service_params.fourcc = FUNC_FOURCC;
|
||||
service_params.callback = func_clnt_callback;
|
||||
service_params.userdata = (void*)1;
|
||||
service_params.version = 1;
|
||||
service_params.version_min = 1;
|
||||
EXPECT(vchiq_open_service_params(instance, &service_params, &service), VCHIQ_ERROR); // Still the wrong version number
|
||||
service_params.version = 4;
|
||||
service_params.version_min = 4;
|
||||
EXPECT(vchiq_open_service_params(instance, &service_params, &service), VCHIQ_ERROR); // Still the wrong version number
|
||||
service_params.version_min = 2;
|
||||
EXPECT(vchiq_open_service_params(instance, &service_params, &service), VCHIQ_SUCCESS); // That's better
|
||||
EXPECT(vchiq_open_service(instance, VCHIQ_MAKE_FOURCC('n','o','n','e'), func_clnt_callback, (void*)2, &service2), VCHIQ_ERROR); // no listener
|
||||
EXPECT(vchiq_open_service(instance, FUNC_FOURCC, func_clnt_callback, (void*)2, &service2), VCHIQ_SUCCESS);
|
||||
EXPECT(vchiq_open_service(instance, FUNC_FOURCC, func_clnt_callback, (void*)3, &service3), VCHIQ_ERROR); // no more listeners
|
||||
EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_ERROR); // Still the wrong version number
|
||||
service_params.version = VCHIQ_TEST_VER + 1;
|
||||
service_params.version_min = VCHIQ_TEST_VER + 1;
|
||||
EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_ERROR); // Still the wrong version number
|
||||
service_params.version = VCHIQ_TEST_VER;
|
||||
service_params.version_min = VCHIQ_TEST_VER;
|
||||
EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_SUCCESS); // That's better
|
||||
|
||||
INIT_PARAMS(&service_params, VCHIQ_MAKE_FOURCC('n','o','n','e'), func_clnt_callback, (void*)2, VCHIQ_TEST_VER);
|
||||
EXPECT(vchiq_open_service(instance, &service_params, &service2), VCHIQ_ERROR); // no listener
|
||||
INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, (void*)2, VCHIQ_TEST_VER);
|
||||
EXPECT(vchiq_open_service(instance, &service_params, &service2), VCHIQ_SUCCESS);
|
||||
INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, (void*)3, VCHIQ_TEST_VER);
|
||||
EXPECT(vchiq_open_service(instance, &service_params, &service3), VCHIQ_ERROR); // no more listeners
|
||||
EXPECT(vchiq_remove_service(service2), VCHIQ_SUCCESS);
|
||||
EXPECT(vchiq_open_service(instance, FUNC_FOURCC, func_clnt_callback, (void*)2, &service2), VCHIQ_SUCCESS);
|
||||
INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, (void*)2, VCHIQ_TEST_VER);
|
||||
EXPECT(vchiq_open_service(instance, &service_params, &service2), VCHIQ_SUCCESS);
|
||||
|
||||
elements[0].data = "a";
|
||||
elements[0].size = 1;
|
||||
@@ -681,8 +859,9 @@ do_functional_test(void)
|
||||
|
||||
vcos_event_wait(&func_test_sync);
|
||||
|
||||
EXPECT(vchiq_open_service(instance, FUNC_FOURCC, func_clnt_callback, (void*)0, &service), VCHIQ_ERROR); /* Instance not initialised */
|
||||
EXPECT(vchiq_add_service(instance, FUNC_FOURCC, func_clnt_callback, (void*)0, &service), VCHIQ_ERROR); /* Instance not initialised */
|
||||
INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, NULL, VCHIQ_TEST_VER);
|
||||
EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_ERROR); /* Instance not initialised */
|
||||
EXPECT(vchiq_add_service(instance, &service_params, &service), VCHIQ_ERROR); /* Instance not initialised */
|
||||
EXPECT(vchiq_connect(instance), VCHIQ_ERROR); /* Instance not initialised */
|
||||
|
||||
bulk_tests_only:
|
||||
@@ -692,7 +871,11 @@ bulk_tests_only:
|
||||
|
||||
func_data_test_iter = 0;
|
||||
|
||||
EXPECT(vchiq_open_service(instance, FUN2_FOURCC, fun2_clnt_callback, (void*)0, &service), VCHIQ_SUCCESS);
|
||||
INIT_PARAMS(&service_params, FUN2_FOURCC, fun2_clnt_callback, NULL, VCHIQ_TEST_VER);
|
||||
EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_SUCCESS);
|
||||
|
||||
if (func_data_test_end < func_data_test_start)
|
||||
goto skip_bulk_tests;
|
||||
|
||||
for (size = 1; size < 64; size++)
|
||||
{
|
||||
@@ -727,6 +910,8 @@ bulk_tests_only:
|
||||
}
|
||||
}
|
||||
|
||||
skip_bulk_tests:
|
||||
|
||||
EXPECT(vchiq_shutdown(instance), VCHIQ_SUCCESS);
|
||||
|
||||
vcos_event_delete(&func_test_sync);
|
||||
@@ -1049,7 +1234,7 @@ func_data_test(VCHIQ_SERVICE_HANDLE_T service, int datalen, int align, int serve
|
||||
|
||||
for (i = 0; i < PROLOGUE_SIZE; i++)
|
||||
{
|
||||
if (prologue[i] != ((i == PROLOGUE_SIZE - 1) ? '\xfe' : '\xff'))
|
||||
if (prologue[i] != (uint8_t)((i == PROLOGUE_SIZE - 1) ? '\xfe' : '\xff'))
|
||||
{
|
||||
vcos_log_error("%d: Prologue corrupted at %x (datalen %x, align %x, server_align %x) -> %02x", func_data_test_iter, i, datalen, align, server_align, prologue[i]);
|
||||
VCOS_BKPT;
|
||||
@@ -1059,7 +1244,7 @@ func_data_test(VCHIQ_SERVICE_HANDLE_T service, int datalen, int align, int serve
|
||||
}
|
||||
for (i = 0; i < EPILOGUE_SIZE; i++)
|
||||
{
|
||||
if (epilogue[i] != ((i == 0) ? '\xfe' : '\xff'))
|
||||
if (epilogue[i] != (uint8_t)((i == 0) ? '\xfe' : '\xff'))
|
||||
{
|
||||
vcos_log_error("%d: Epilogue corrupted at %x (datalen %x, align %x, server_align %x) -> %02x", func_data_test_iter, i, datalen, align, server_align, epilogue[i]);
|
||||
VCOS_BKPT;
|
||||
@@ -1140,6 +1325,7 @@ clnt_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
|
||||
ctrl_received++;
|
||||
if (g_server_error || (ctrl_received == g_params.iters))
|
||||
vcos_event_signal(&g_shutdown);
|
||||
vchiq_release_message(service, header);
|
||||
}
|
||||
else if (header->size != 0)
|
||||
g_server_error = header->data;
|
||||
@@ -1407,6 +1593,8 @@ static void usage(void)
|
||||
printf(" -q disable data verification\n");
|
||||
printf(" -s ???? service (any 4 characters)\n");
|
||||
printf(" -v enable more verbose output\n");
|
||||
printf(" -r <b> <s> reserve <b> bytes for <s> seconds\n");
|
||||
printf(" -K <t> send a SIGKILL after <t> ms\n");
|
||||
printf(" and <mode> is one of:\n");
|
||||
printf(" -c <size> control test (size in bytes)\n");
|
||||
printf(" -b <size> bulk test (size in kilobytes)\n");
|
||||
@@ -1441,6 +1629,60 @@ static char *buf_align(char *buf, int align_size, int align)
|
||||
return aligned;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
|
||||
static void kill_timeout_handler(int cause, siginfo_t *how, void *ucontext)
|
||||
{
|
||||
printf("Sending signal SIGKILL\n");
|
||||
kill(main_process_pid, SIGKILL);
|
||||
}
|
||||
|
||||
static int setup_auto_kill(int timeout_ms)
|
||||
{
|
||||
long timeout;
|
||||
struct timeval interval;
|
||||
|
||||
if (timeout_ms <= 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
timeout = 1000 * timeout_ms;
|
||||
|
||||
/* install a signal handler for the alarm */
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(struct sigaction));
|
||||
sa.sa_sigaction = kill_timeout_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
if (sigaction(SIGALRM, &sa, 0))
|
||||
{
|
||||
perror("sigaction");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* when to expire */
|
||||
interval.tv_sec = timeout / 1000000;
|
||||
interval.tv_usec = timeout % 1000000;
|
||||
|
||||
struct itimerval alarm_spec = {
|
||||
.it_interval = {0,0},
|
||||
.it_value = interval
|
||||
};
|
||||
|
||||
int rc = setitimer(ITIMER_REAL, &alarm_spec, NULL);
|
||||
if (rc < 0)
|
||||
{
|
||||
perror("setitimer failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef VCOS_APPLICATION_INITIALIZE
|
||||
|
||||
static VCOS_THREAD_T Task_0;
|
||||
@@ -1480,6 +1722,10 @@ void VCOS_APPLICATION_INITIALIZE(void *first_available_memory)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifdef ANDROID
|
||||
main_process_pid = getpid();
|
||||
#endif
|
||||
|
||||
vcos_init();
|
||||
vcos_use_android_log = 0;
|
||||
return vchiq_test(argc, argv);
|
||||
|
||||
@@ -23,7 +23,7 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
*/
|
||||
|
||||
#ifndef VCHIQ_TEST_H
|
||||
#define VCHIQ_TEST_H
|
||||
@@ -43,6 +43,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define FUN2_MAX_ALIGN 4096
|
||||
#define BULK_ALIGN_SIZE 4096
|
||||
|
||||
#define VCHIQ_TEST_VER 3
|
||||
|
||||
enum {
|
||||
MSG_ERROR,
|
||||
MSG_ONEWAY,
|
||||
|
||||
@@ -69,6 +69,11 @@ int vchiu_queue_is_empty(VCHIU_QUEUE_T *queue)
|
||||
return queue->read == queue->write;
|
||||
}
|
||||
|
||||
int vchiu_queue_is_full(VCHIU_QUEUE_T *queue)
|
||||
{
|
||||
return queue->write == queue->read + queue->size;
|
||||
}
|
||||
|
||||
void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header)
|
||||
{
|
||||
while (queue->write == queue->read + queue->size)
|
||||
|
||||
@@ -23,7 +23,7 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
*/
|
||||
|
||||
#ifndef VCHIQ_UTIL_H
|
||||
#define VCHIQ_UTIL_H
|
||||
@@ -46,6 +46,7 @@ extern int vchiu_queue_init(VCHIU_QUEUE_T *queue, int size);
|
||||
extern void vchiu_queue_delete(VCHIU_QUEUE_T *queue);
|
||||
|
||||
extern int vchiu_queue_is_empty(VCHIU_QUEUE_T *queue);
|
||||
extern int vchiu_queue_is_full(VCHIU_QUEUE_T *queue);
|
||||
|
||||
extern void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header);
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "interface/vcos/vcos.h"
|
||||
#ifdef __VIDEOCORE__
|
||||
#include "host_support/include/vc_debug_sym.h"
|
||||
#include "vcfw/vclib/vclib.h"
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -54,6 +55,8 @@ int vcos_verify_bkpts_enable(int enable)
|
||||
*/
|
||||
void vcos_abort(void)
|
||||
{
|
||||
VCOS_ALERT("vcos_abort: Halting");
|
||||
|
||||
#ifdef __VIDEOCORE__
|
||||
_bkpt();
|
||||
#endif
|
||||
@@ -62,6 +65,11 @@ void vcos_abort(void)
|
||||
vcos_backtrace_self();
|
||||
#endif
|
||||
|
||||
#ifdef __VIDEOCORE__
|
||||
/* Flush the cache to help with postmortem RAM-dump debugging */
|
||||
vclib_cache_flush();
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_RASPBERRYPI
|
||||
extern void pattern(int);
|
||||
while(1)
|
||||
|
||||
@@ -24,6 +24,44 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*****************************************************************************
|
||||
* Copyright 2012 Broadcom Corporation. All rights reserved.
|
||||
*
|
||||
* This program is the proprietary software of Broadcom Corporation and/or
|
||||
* its licensors, and may only be used, duplicated, modified or distributed
|
||||
* pursuant to the terms and conditions of a separate, written license
|
||||
* agreement executed between you and Broadcom (an "Authorized License").
|
||||
* Except as set forth in an Authorized License, Broadcom grants no license
|
||||
* (express or implied), right to use, or waiver of any kind with respect to
|
||||
* the Software, and Broadcom expressly reserves all rights in and to the
|
||||
* Software and all intellectual property rights therein. IF YOU HAVE NO
|
||||
* AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS SOFTWARE IN ANY
|
||||
* WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE ALL USE OF
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* Except as expressly set forth in the Authorized License,
|
||||
* 1. This program, including its structure, sequence and organization,
|
||||
* constitutes the valuable trade secrets of Broadcom, and you shall use
|
||||
* all reasonable efforts to protect the confidentiality thereof, and to
|
||||
* use this information only in connection with your use of Broadcom
|
||||
* integrated circuit products.
|
||||
* 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
|
||||
* AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR
|
||||
* WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
|
||||
* RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY DISCLAIMS ANY AND ALL
|
||||
* IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS,
|
||||
* QUIET ENJOYMENT, QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. YOU
|
||||
* ASSUME THE ENTIRE RISK ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE.
|
||||
* 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS
|
||||
* LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT,
|
||||
* OR EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
|
||||
* YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS
|
||||
* OF THE AMOUNT ACTUALLY PAID FOR THE SOFTWARE ITSELF OR U.S. $1, WHICHEVER
|
||||
* IS GREATER. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
|
||||
* ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "interface/vcos/vcos.h"
|
||||
|
||||
|
||||
@@ -148,6 +148,8 @@ static VCOS_MSGQUEUE_T *vcos_msgq_find_helper(const char *name, int wait)
|
||||
|
||||
/* we're now on the list, so can safely go to sleep */
|
||||
vcos_mutex_unlock(&lock);
|
||||
|
||||
/* coverity[lock] This is a semaphore, not a mutex */
|
||||
vcos_semaphore_wait(&waiter.sem);
|
||||
/* It should now be on the list, but it could in theory be deleted
|
||||
* between waking up and going to look for it. So may have to wait
|
||||
|
||||
@@ -25,6 +25,11 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*=============================================================================
|
||||
FIXME: This code should be moved to 'linux', it is linux-specific and not generic
|
||||
on 'pthreads'.
|
||||
============================================================================*/
|
||||
|
||||
#ifndef VCOS_MUTEX_FROM_FUTEX_H
|
||||
#define VCOS_MUTEX_FROM_FUTEX_H
|
||||
|
||||
|
||||
4
interface/vcos/pthreads/vcos_platform.h
Normal file → Executable file
4
interface/vcos/pthreads/vcos_platform.h
Normal file → Executable file
@@ -25,6 +25,10 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*=============================================================================
|
||||
VideoCore OS Abstraction Layer - pthreads types
|
||||
=============================================================================*/
|
||||
|
||||
/* Do not include this file directly - instead include it via vcos.h */
|
||||
|
||||
/** @file
|
||||
|
||||
@@ -25,6 +25,10 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*=============================================================================
|
||||
VideoCore OS Abstraction Layer - platform-specific types and defines
|
||||
=============================================================================*/
|
||||
|
||||
#ifndef VCOS_PLATFORM_TYPES_H
|
||||
#define VCOS_PLATFORM_TYPES_H
|
||||
|
||||
|
||||
47
interface/vcos/user_nodefs.h
Normal file
47
interface/vcos/user_nodefs.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright (c) 2012, Broadcom Europe Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef USER_NODEFS_H
|
||||
#define USER_NODEFS_H
|
||||
|
||||
/*
|
||||
* This tells coverity not to expand the assert macro, so it still sees the
|
||||
* asserts in the code, even in release builds (we currently run coverity on
|
||||
* our release builds). Unfortunately MetaWare won't compile it, even though
|
||||
* __COVERITY__ isn't defined, so we put this in its own header.
|
||||
*
|
||||
* FIXME: This belongs in the Coverity config (in a file called
|
||||
* config/user_nodefs.h)
|
||||
*/
|
||||
#nodef assert
|
||||
|
||||
/*
|
||||
* So we need to declare the function now that it isn't a macro any more. It's
|
||||
* already built into coverity that assert is a "killpath".
|
||||
*/
|
||||
extern void assert(int cond);
|
||||
|
||||
#endif /* USER_NODEFS_H */
|
||||
@@ -149,13 +149,15 @@ extern "C" {
|
||||
#include "interface/vcos/vcos_types.h"
|
||||
|
||||
#ifdef __COVERITY__
|
||||
#include "interface/vcos/user_nodefs.h"
|
||||
|
||||
extern void __coverity_panic__(void);
|
||||
#undef VCOS_ASSERT_BKPT
|
||||
#define VCOS_ASSERT_BKPT __coverity_panic__()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ANDROID should NOT be defined for files built for Videcore, but currently it
|
||||
* ANDROID should NOT be defined for files built for Videocore, but currently it
|
||||
* is. FIXME When that's fixed, remove the __VIDEOCORE__ band-aid.
|
||||
*/
|
||||
#if (defined(ANDROID) && !defined(__VIDEOCORE__))
|
||||
@@ -210,6 +212,16 @@ extern void logging_assert_dump(void);
|
||||
#endif
|
||||
|
||||
#if !defined(NDEBUG) || defined(VCOS_RELEASE_ASSERTS)
|
||||
#define VCOS_ASSERT_ENABLED 1
|
||||
#define VCOS_VERIFY_ENABLED 1
|
||||
#else
|
||||
#define VCOS_ASSERT_ENABLED 0
|
||||
#define VCOS_VERIFY_ENABLED 0
|
||||
#endif
|
||||
|
||||
#define VCOS_DEMAND_ENABLED 1
|
||||
|
||||
#if VCOS_ASSERT_ENABLED
|
||||
|
||||
#ifndef vcos_assert
|
||||
#define vcos_assert(cond) \
|
||||
@@ -221,7 +233,7 @@ extern void logging_assert_dump(void);
|
||||
( (cond) ? (void)0 : (VCOS_ASSERT_MSG(__VA_ARGS__), VCOS_ASSERT_BKPT) )
|
||||
#endif
|
||||
|
||||
#else /* !defined(NDEBUG) || defined(VCOS_RELEASE_ASSERTS) */
|
||||
#else /* VCOS_ASSERT_ENABLED */
|
||||
|
||||
#ifndef vcos_assert
|
||||
#define vcos_assert(cond) (void)0
|
||||
@@ -231,9 +243,10 @@ extern void logging_assert_dump(void);
|
||||
#define vcos_assert_msg(cond, ...) (void)0
|
||||
#endif
|
||||
|
||||
#endif /* !defined(NDEBUG) || defined(VCOS_RELEASE_ASSERTS) */
|
||||
#endif /* VCOS_ASSERT_ENABLED */
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
|
||||
#if VCOS_DEMAND_ENABLED
|
||||
|
||||
#ifndef vcos_demand
|
||||
#define vcos_demand(cond) \
|
||||
@@ -245,17 +258,7 @@ extern void logging_assert_dump(void);
|
||||
( (cond) ? (void)0 : (VCOS_ASSERT_MSG(__VA_ARGS__), VCOS_ASSERT_BKPT, vcos_abort()) )
|
||||
#endif
|
||||
|
||||
#ifndef vcos_verify
|
||||
#define vcos_verify(cond) \
|
||||
( (cond) ? 1 : (VCOS_VERIFY_MSG("%s", #cond), VCOS_VERIFY_BKPT, 0) )
|
||||
#endif
|
||||
|
||||
#ifndef vcos_verify_msg
|
||||
#define vcos_verify_msg(cond, ...) \
|
||||
( (cond) ? 1 : (VCOS_VERIFY_MSG(__VA_ARGS__), VCOS_VERIFY_BKPT, 0) )
|
||||
#endif
|
||||
|
||||
#else /* !defined(NDEBUG) */
|
||||
#else /* VCOS_DEMAND_ENABLED */
|
||||
|
||||
#ifndef vcos_demand
|
||||
#define vcos_demand(cond) \
|
||||
@@ -267,6 +270,23 @@ extern void logging_assert_dump(void);
|
||||
( (cond) ? (void)0 : vcos_abort() )
|
||||
#endif
|
||||
|
||||
#endif /* VCOS_DEMAND_ENABLED */
|
||||
|
||||
|
||||
#if VCOS_VERIFY_ENABLED
|
||||
|
||||
#ifndef vcos_verify
|
||||
#define vcos_verify(cond) \
|
||||
( (cond) ? 1 : (VCOS_VERIFY_MSG("%s", #cond), VCOS_VERIFY_BKPT, 0) )
|
||||
#endif
|
||||
|
||||
#ifndef vcos_verify_msg
|
||||
#define vcos_verify_msg(cond, ...) \
|
||||
( (cond) ? 1 : (VCOS_VERIFY_MSG(__VA_ARGS__), VCOS_VERIFY_BKPT, 0) )
|
||||
#endif
|
||||
|
||||
#else /* VCOS_VERIFY_ENABLED */
|
||||
|
||||
#ifndef vcos_verify
|
||||
#define vcos_verify(cond) (cond)
|
||||
#endif
|
||||
@@ -275,7 +295,8 @@ extern void logging_assert_dump(void);
|
||||
#define vcos_verify_msg(cond, ...) (cond)
|
||||
#endif
|
||||
|
||||
#endif /* !defined(NDEBUG) */
|
||||
#endif /* VCOS_VERIFY_ENABLED */
|
||||
|
||||
|
||||
#ifndef vcos_static_assert
|
||||
#if defined(__GNUC__)
|
||||
|
||||
@@ -25,6 +25,10 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*=============================================================================
|
||||
VideoCore OS Abstraction Layer - fixed size allocator support
|
||||
=============================================================================*/
|
||||
|
||||
#ifndef VCOS_BLOCKPOOL_H
|
||||
#define VCOS_BLOCKPOOL_H
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user