Update master branch to next

This commit is contained in:
Dom Cobley
2012-12-27 19:00:17 +00:00
parent 83e1597d57
commit 9852ce2882
154 changed files with 9364 additions and 1581 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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 );
}

View File

@@ -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)

View File

@@ -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 )
{

View File

@@ -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 ------------------------------------------------- */

View File

@@ -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

View File

@@ -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, &params, &vchiq_khan_service);
params.fourcc = FOURCC_KHRN;
params.callback = khrn_callback;
khrn_return = vchiq_open_service(khrn_vchiq_instance, &params, &vchiq_khrn_service);
params.fourcc = FOURCC_KHHN;
params.callback = khhn_callback;
khhn_return = vchiq_open_service(khrn_vchiq_instance, &params, &vchiq_khhn_service);
if (khan_return != VCHIQ_SUCCESS ||
khrn_return != VCHIQ_SUCCESS ||
khhn_return != VCHIQ_SUCCESS)
{
vcos_log_error("* failed to add service - already in use?");

File diff suppressed because it is too large Load Diff

View File

@@ -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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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')

View File

@@ -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);

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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 */

View 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;
}

View 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 */

View File

@@ -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();
}
/*****************************************************************************

View File

@@ -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.

View File

@@ -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 */

View File

@@ -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);
}
}

View File

@@ -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;
}

View 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);
}

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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

View 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 */

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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 */
/* @} */

View File

@@ -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__)

View File

@@ -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 */

View 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 */

View File

@@ -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 */

View 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 */

View File

@@ -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 */

View File

@@ -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

View File

@@ -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

View File

@@ -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 */

View File

@@ -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

View File

@@ -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)

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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.

View File

@@ -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},
};

View File

@@ -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

View 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);
}

View File

@@ -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 */

View File

@@ -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)
{

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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)
*
*/

View File

@@ -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, &param.hdr);
if (status == MMAL_SUCCESS)
*value = param.enable;
return status;
}
/** Helper function to set the value of a 64 bits unsigned integer parameter */
MMAL_STATUS_T mmal_port_parameter_set_uint64(MMAL_PORT_T *port, uint32_t id, uint64_t value)
{
MMAL_PARAMETER_UINT64_T param = {{id, sizeof(param)}, value};
return mmal_port_parameter_set(port, &param.hdr);
}
/** Helper function to get the value of a 64 bits unsigned integer parameter */
MMAL_STATUS_T mmal_port_parameter_get_uint64(MMAL_PORT_T *port, uint32_t id, uint64_t *value)
{
MMAL_PARAMETER_UINT64_T param = {{id, sizeof(param)}, 0LL};
// coverity[overrun-buffer-val] Structure accessed correctly via size field
MMAL_STATUS_T status = mmal_port_parameter_get(port, &param.hdr);
if (status == MMAL_SUCCESS)
*value = param.value;
return status;
}
/** Helper function to set the value of a 64 bits signed integer parameter */
MMAL_STATUS_T mmal_port_parameter_set_int64(MMAL_PORT_T *port, uint32_t id, int64_t value)
{
MMAL_PARAMETER_INT64_T param = {{id, sizeof(param)}, value};
return mmal_port_parameter_set(port, &param.hdr);
}
/** Helper function to get the value of a 64 bits signed integer parameter */
MMAL_STATUS_T mmal_port_parameter_get_int64(MMAL_PORT_T *port, uint32_t id, int64_t *value)
{
MMAL_PARAMETER_INT64_T param = {{id, sizeof(param)}, 0LL};
// coverity[overrun-buffer-val] Structure accessed correctly via size field
MMAL_STATUS_T status = mmal_port_parameter_get(port, &param.hdr);
if (status == MMAL_SUCCESS)
*value = param.value;
return status;
}
/** Helper function to set the value of a 32 bits unsigned integer parameter */
MMAL_STATUS_T mmal_port_parameter_set_uint32(MMAL_PORT_T *port, uint32_t id, uint32_t value)
{
MMAL_PARAMETER_INT32_T param = {{id, sizeof(param)}, value};
MMAL_PARAMETER_UINT32_T param = {{id, sizeof(param)}, value};
return mmal_port_parameter_set(port, &param.hdr);
}
/** Helper function to get the value of a 32 bits unsigned integer parameter */
MMAL_STATUS_T mmal_port_parameter_get_uint32(MMAL_PORT_T *port, uint32_t id, uint32_t *value)
{
MMAL_PARAMETER_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, &param.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, &param.hdr);
}
/** Helper function to get the value of a 32 bits signed integer parameter */
MMAL_STATUS_T mmal_port_parameter_get_int32(MMAL_PORT_T *port, uint32_t id, int32_t *value)
{
MMAL_PARAMETER_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, &param.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, &param.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, &param->hdr);
free(param);
return status;
}
/** Helper function to set a MMAL_PARAMETER_URI_T parameter on a port */
MMAL_STATUS_T mmal_util_port_set_uri(MMAL_PORT_T *port, const char *uri)
{
return mmal_port_parameter_set_string(port, MMAL_PARAMETER_URI, uri);
}
/** Helper function to set the value of an array of bytes parameter */
MMAL_STATUS_T mmal_port_parameter_set_bytes(MMAL_PORT_T *port, uint32_t id,
const uint8_t *data, unsigned int size)
{
MMAL_PARAMETER_BYTES_T *param = 0;
MMAL_STATUS_T status;
size_t param_size = sizeof(param->hdr) + size;
param = calloc(1, param_size);
if (!param)
return MMAL_ENOMEM;
param->hdr.id = id;
param->hdr.size = param_size;
memcpy(param->data, data, size);
status = mmal_port_parameter_set(port, &param->hdr);
free(param);
return status;
@@ -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(&param, 0, sizeof(param));
param.hdr.id = MMAL_PARAMETER_CORE_STATISTICS;
param.hdr.size = sizeof(param);
param.dir = dir;
param.reset = reset;
// coverity[overrun-buffer-val] Structure accessed correctly via size field
ret = mmal_port_parameter_get(port, &param.hdr);
if (ret == MMAL_SUCCESS)
*stats = param.stats;

View File

@@ -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

View 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;
}

View 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

View File

@@ -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)

View File

@@ -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++)
{

View File

@@ -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

View 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;
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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);

View File

@@ -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)

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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_

View File

@@ -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_

View File

@@ -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 );

View 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.
*/
// 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_

View File

@@ -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_

View File

@@ -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
View 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
View 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
View 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)

View File

@@ -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, &params, 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, &params, 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(&params, 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,
&params,
@@ -1171,6 +1185,8 @@ vchi_service_create( VCHI_INSTANCE_T instance_handle,
memset(&params, 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,
&params,
@@ -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;
}

View File

@@ -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);

View 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_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,

View File

@@ -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)

View 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_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);

View File

@@ -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)

View File

@@ -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"

View File

@@ -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

View File

@@ -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
View 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

View 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

View 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 */

View File

@@ -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__)

View 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 - 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