Analyze This…
Directed by Harold Ramis
Starring Robert DeNiro, Billy Crystal, Lisa Kudrow, and Chazz Plamantari
As Reviewed by James Brundage
We've seen it before. We've seen Bobby DeNiro as a gangster in Godfather, Part II, in countless Martin Scorcese films, as Al Capone in The Untouchables. But, what we haven't seen before is the humor. Never before has Robert DeNiro tried to parody himself, to make fun of his own standards and stereotypes. Sure, we don't get a parody of the monologue from Taxi Driver (`You talkin' to me?'), but we get a steady does of mob film spoofs, including a shot-by-shot parody of The Godfather.
Harold Ramis takes the helm of this risky project about the original risky business. Paul Viti (Robert DeNiro) is a mobster with issues. His best friend has just been killed, and, to be honest, he's conflicted about being his harsh old self. He's having panic attacks, he's not willing to beat information out of someone. Let's face it, it's crimpin his style. So, taking advantage of a run-in (literally, Billy Crystal hits the back of a sedan with a person on his way to be killed in it) with psychiatrist Ben Sobol, he starts going to a shrink.
Sobol is just your garden-variety shrink, leaning a little too much towards the `Fraiser' side. His son's a smart Alec, his fiancée (Kudrow) is a bimbo. He listens to the problems of neurotics all day long. Of course, when a gangster steps in the door, everything changes.
Viti starts following him everywhere. He becomes his only client because he need to have a therapeutic breakthrough before a meeting of the heads of all the families in two weeks.
The fact is, though, that we have seen this before. This was the plot of The Don's Analyst, with Robert Loggia. It's also the plot of the HBO Series The Sopranos. However, Analyze This… does it's job much better than The Don's Analyst, which was dry and unfunny, ever could.
Despite the fact that the script was plagued by last-minute rewrites and a director who's only product that I've seen and respected was the moderately creative (although now hackneyed) Groundhog's Day, it actually doesn't seem as openly contrived. It does its job: mix humor with a serious plot fairly well, and it's fun to see Robert DeNiro break into tears at a Prudential commercial. Robert DeNiro, too, does his job. He turns out a performance that's good… for him, a man who has won two academy awards and is one of America's finest living actors.
The real disappointment in the film, despite a lack of originality in plot is Billy Crystal. Crystal turns out a lackluster performance as the psychiatrist, and seems to merely sit around and be glad he landed a role with DeNiro at all. He delivers a few good scenes, such as the one where he tries to act like the consillieri. Lisa Kurdrow also does a good job as the bimbo fiancée.
As I've said, there aren't that many holes in the script. One little thing that bothers me is that, considering how much Kudrow seems to hate Crystal, she ends up with everything honky-dory with him at the end. Once again, idiotic characters are constructed, but that's the price that is paid for a funny movie, and it is a funny movie.
Analyze This… isn't really quality cinema, but it's fun. It's fun to see people parody themselves. It's fun to watch someone admit that they've been doing to same part for so long (albeit, doing it great). It's also fun to watch this film, and is one definitely worth heading out to the theatre to see.
The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


Using Blockchain, taxi drivers can for the first time cut the middleman and connect directly with passengers, creating a true peer-to-peer network
Anyone can build their own version of the ride hailing app, and get instant access to all driver and passengers pools on the DAV network


Hyellow
Find Love
Make a Free Account Today!
Find Friends
Everyone deserves a chance
See how it works
Join
Log In


Facts About Me
Hello, my name is Connor Stern and I am a webpage designer, minoring in marketing living in Pennsylvania. I am currently a senior enrolled in Pennsylvania College of Technology and I love to make cool and creative website designs reguardless of the meduim I'm working in.
Dedicated to working as hard as I can.
I love traveling and visiting new places.
Aside from designing webpages I am a master fisherman.
I have been told that I am very easy to get along with.
I love taking pictures everywhere I travel.
I have a strong amount of cofidence in public speaking.
Education
I spent all my years in school in Hamburg Area. I graduated from Hamburg Area Highschool in 2012.  Although I did not take any web page classes in highschool, I took many art classes which helped me in my design part of web page designing. Playing sports throughout highschool probably taught me the most with leadership and stepping up when I need too. I was captain my junior and senior year. I played the last defender on the field so I controlled the whole field from the back and made sure everyone knew where they were supposed to be.
Skill Set
This bar shows my set of skills in the use of HTML/CSS, Photoshop, PHP, and javascript. I have been doing HTML and CSS for about 4 years and I have learned many tricks and I am very skilled in them. I have been using photoshop on and off for four years also but recently I have been using it more and increasing my skils. I took a year of PHP and learned some cool tricks to do with it. I learned Javascript last year and have basic skills but can do cool things with it.


OpenMAX and OpenSL are open standards from the Khronos group that are designed for low capability devices. Vendors of cards are expected to produce implementations. There is little by way of general Linux implementations, but Broadcom have implemented one of the specifications (OpenMAX IL), and their chip is used in the Raspberry Pi. Other specifications (OpenMAX AL and OpenSL ES) are expected to be implemented in Android devices, accessible by the Native Development Kit (NDK).
"The Khronos Group is a not for profit industry consortium creating open standards for the authoring and acceleration of parallel computing, graphics, dynamic media, computer vision and sensor processing on a wide variety of platforms and devices". For this book, the relevant standards that they produce are OpenSL (not to be confused with OpenGL - a graphics specification) and OpenMAX.
OpenSL and OpenMAX are intended for slightly different uses, but have an overlap
of functionality. From the OpenSL ES and OpenMAX Al specifications this is shown by the
following figure:
OpenSL is intended for complex audio systems while OpenMAX is intended for
general multi-media systems. Either can be used separately, or if needed
both can be used - in the overlapping area the functionality is the same
(even though the function calls are distinct).
Each of these is further divided into profiles. For OpenSL the profiles are
with optional functionality in
A full chart of features in each profile is given in the specification.
OpenMAX has profiles
with optional functionality in
A full chart of features in each profile is given in the specification.
Just to complicate things a little, OpenSL only has one specification, OpenSL ES (no, I don't know what ES stands for). On the other hand, OpenMAX has two specified layers, OpenMAX IL (interface layer) and OpenMAX AL (application layer). The APIs for OpenSL ES and OpenMAX AL mirror each other in the common area. The API for OpenMAX IL is at a considerably lower level than the API for OpenMAX AL, and is discussed in a later section.
The specifications give some examples on how the different profiles might be mixed:
- Example 1: an audio-only application will have no need for video and image functionality and therefore would likely pick one of the OpenSL ES profiles, depending on the use cases of interest.
- Example 2: a media playback and recording application would use the OpenMAX AL 1.0 Media Player/Recorder profile.
- Example 3: An advanced multimedia/game application that needs audio/video/image playback and recording as well as advanced audio features like 3D audio and effects would use both the Media Player/Recorder profile of OpenMAX AL 1.0 and the Game profile of OpenSL ES 1.0.
It is expected that OpenMAX and OpenSL will find their major uses in situations where the CPU and memory are limited, but where there is the possibility of hardware acceleration of video and audio by e.g. a GPU. Consequently, the situation for general Linux systems is poor. Bellagio has an implementation of OpenMAX IL. LIM has an implementation of both OpenMAX AL and IL.
I have not been able to find any OpenSL ES implementations for general Linux.
The Raspberry Pi supports OpenMAX IL from the Broadcom card included. If you download the firmware master from the Raspberry Pi download site, a number of examples are included such as firmware-master/documentation/ilcomponents/audio_mixer.html. These are not "pure" OpenMAX IL: they make use of a Broadcom convenience package and also use some vendor extension APIs beyond the OpenMAX IL standard.
You write Android apps in Java. But like most Java systems, code written in C or C++ can be included as "native" methods. The native code is linked by a framework called JNI (Java Native Interface). For the Android, Google have standardised a number of libraries in the NDK (Native Development Kit). This includes both OpenSL ES and OpenMAX AL. Informaton about these is included in the Android NDK .
Documents in the NDK such as android-ndk-r8d/docs/opensles/index.html give good overviews of using these, although using the JNI to build applications is not for the faint of heart. In addition, the documentation inlcudes comments like "In particular, use of OpenSL ES does not guarantee a lower audio latency, higher scheduling priority, etc. than what the platform generally provides". From Android 4.2 on, lower latency will be possible using OpenSL ES. See the Performance section in opensles/index.html
See android-ndk-r8d/samples/native-audio for an example using Java + JNI + OpenSL ES.
These examples are taken from the appendices of the OpenSL ES specification.
The programming model for OpenSL ES is that of interfaces and objects. The programming language is C, so one of the common mechanisms for writing O/O style code in C is used (see e.g. Object-Oriented Programming In C ). Interfaces are represented by structures containing function pointers for methods. An object which implements the interface is of the interface type, with the methods as particular functions. Calling a method involves calling the appropriate function in the structure. The "this" object is always passed in as the first parameter of the function as in
(*object) -> method(object, ...)
Every object has to be "realised" before it can be used.
There does not seem to be any inheritance model, but then that isn't necessary here.
Note that every function returns a value that can be tested for sucess or fail.
Objects that are created are passed as address parameters for filling.
The application is responsible for freeing any memory allocated during this
by calling Destroy()
on the object.
An OpenSL (or OpenMAX AL) application is started by creating an "engine" using
slCreateEngine()
. This is the only global function in the library.
From then on, objects are obtained from the engine or other objects by a call
to GetInterface()
or CreateXYZ
on the engine or object.
For example,
(*engine) -> CreateOutputMix(engine, &output_mix...);
(*output_mix) -> GetInterface(output_mix, SL_IID_VOLUME, &volume, ...);
The model for playing audio is not very complex, just verbose. It consists of
SLresult res;
SLObjectItf sl;
SLEngineOption EngineOption[] = {
(SLuint32) SL_ENGINEOPTION_THREADSAFE,
(SLuint32) SL_BOOLEAN_TRUE};
res = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL);
CheckErr(res);
/* Realizing the SL Engine in synchronous mode. */
res = (*sl)->Realize(sl, SL_BOOLEAN_FALSE); CheckErr(res);
/* Local storage for Audio data */
SLint16 pcmData[AUDIO_DATA_STORAGE_SIZE];
/* put something nito pcmData ... not done here */
/* Setup the data source structure for the buffer queue */
bufferQueue.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
bufferQueue.numBuffers = 4; /* Four buffers in our buffer queue */
/* Setup the format of the content in the buffer queue */
pcm.formatType = SL_DATAFORMAT_PCM;
pcm.numChannels = 2;
pcm.samplesPerSec = SL_SAMPLINGRATE_44_1;
pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
pcm.containerSize = 16;
pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
audioSource.pFormat = (void *)&pcm;
audioSource.pLocator = (void *)&bufferQueue;
for (i=0;i<MAX_NUMBER_INTERFACES;i++)
{
required[i] = SL_BOOLEAN_FALSE;
iidArray[i] = SL_IID_NULL;
}
// Create Output Mix object to be used by player
res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 1,
iidArray, required); CheckErr(res);
// Realizing the Output Mix object in synchronous mode.
res = (*OutputMix)->Realize(OutputMix, SL_BOOLEAN_FALSE);
CheckErr(res);
The callback in this case uses a data structure to hold all of the data and pointers to the start and current position of the data. This is for this application, and is not a part of OpenSL
/* Structure for passing information to callback function */
typedef struct CallbackCntxt_ {
SLPlayItf playItf;
SLint16* pDataBase;
// Base adress of local audio data storage
SLint16* pData;
// Current adress of local audio data storage
SLuint32 size;
} CallbackCntxt;
Then we can set up the output sink and callback data
/* Setup the data sink structure */
locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
locator_outputmix.outputMix = OutputMix;
audioSink.pLocator = (void *)&locator_outputmix;
audioSink.pFormat = NULL;
/* Initialize the context for Buffer queue callbacks */
cntxt.pDataBase = (void*)&pcmData;
cntxt.pData = cntxt.pDataBase;
cntxt.size = sizeof(pcmData);
/* Set arrays required[] and iidArray[] for SEEK interface
(PlayItf is implicit) */
required[0] = SL_BOOLEAN_TRUE;
iidArray[0] = SL_IID_BUFFERQUEUE;
/* Create the music player */
res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player,
&audioSource, &audioSink, 1, iidArray, required); CheckErr(res);
/* Realizing the player in synchronous mode. */
res = (*player)->Realize(player, SL_BOOLEAN_FALSE); CheckErr(res);
/* Get seek and play interfaces */
res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
CheckErr(res);
res = (*player)->GetInterface(player, SL_IID_BUFFERQUEUE,
(void*)&bufferQueueItf); CheckErr(res);
/* Setup to receive buffer queue event callbacks */
res = (*bufferQueueItf)->RegisterCallback(bufferQueueItf,
BufferQueueCallback, NULL); CheckErr(res);
/* Enqueue a few buffers to get the ball rolling */
res = (*bufferQueueItf)->Enqueue(bufferQueueItf, cntxt.pData,
2 * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
CheckErr(res);
cntxt.pData += AUDIO_DATA_BUFFER_SIZE;
res = (*bufferQueueItf)->Enqueue(bufferQueueItf, cntxt.pData,
2 * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
CheckErr(res);
cntxt.pData += AUDIO_DATA_BUFFER_SIZE;
res = (*bufferQueueItf)->Enqueue(bufferQueueItf, cntxt.pData,
2 * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
CheckErr(res);
cntxt.pData += AUDIO_DATA_BUFFER_SIZE;
/* Play the PCM samples using a buffer queue */
res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING );
CheckErr(res);
/* Wait until the PCM data is done playing, the buffer queue callback
will continue to queue buffers until the entire PCM data has been
played. This is indicated by waiting for the count member of the
SLBufferQueueState to go to zero.
*/
res = (*bufferQueueItf)->GetState(bufferQueueItf, &state);
CheckErr(res);
while(state.count)
{
(*bufferQueueItf)->GetState(bufferQueueItf, &state);
}
/* Make sure player is stopped */
res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
CheckErr(res);
/* Destroy the player */
(*player)->Destroy(player);
/* Destroy Output Mix object */
(*OutputMix)->Destroy(OutputMix);
The full code is
The ability to record audio in OpenSL ES is an option for the implementation. Consequently, we cannot guarantee that there is any microphone or similar device. The main difference in this program from the previous one is that checks need to be performed first on the input devices:
res = (*sl)->GetInterface(sl, SL_IID_AUDIOIODEVICECAPABILITIES,
(void*)&AudioIODeviceCapabilitiesItf); CheckErr(res);
numInputs = MAX_NUMBER_INPUT_DEVICES;
res = (*AudioIODeviceCapabilitiesItf)->GetAvailableAudioInputs(
AudioIODeviceCapabilitiesItf, &numInputs, InputDeviceIDs); CheckErr(res);
/* Search for either earpiece microphone or headset microphone input
device - with a preference for the latter */
for (i=0;i < numInputs; i++)
{
res = (*AudioIODeviceCapabilitiesItf)-
>QueryAudioInputCapabilities(AudioIODeviceCapabilitiesItf,
InputDeviceIDs[i], &AudioInputDescriptor); CheckErr(res);
if((AudioInputDescriptor.deviceConnection ==
SL_DEVCONNECTION_ATTACHED_WIRED)&&
(AudioInputDescriptor.deviceScope == SL_DEVSCOPE_USER)&&
(AudioInputDescriptor.deviceLocation ==
SL_DEVLOCATION_HEADSET))
{
mic_deviceID = InputDeviceIDs[i];
mic_available = SL_BOOLEAN_TRUE;
break;
}
else if((AudioInputDescriptor.deviceConnection ==
SL_DEVCONNECTION_INTEGRATED)&&
(AudioInputDescriptor.deviceScope ==
SL_DEVSCOPE_USER)&&
(AudioInputDescriptor.deviceLocation ==
SL_DEVLOCATION_HANDSET))
{
mic_deviceID = InputDeviceIDs[i];
mic_available = SL_BOOLEAN_TRUE;
break;
}
}
/* If neither of the preferred input audio devices is available, no
point in continuing */
if (!mic_available) {
/* Appropriate error message here */
exit(1);
}
The other major differences are that the engine is used to create an audio recorder rather than a player, and that the recorded sounds are saved to a file.
The following example OpenMAX_AL_playback.c is from the OpenMAX AL specification.
The functionality of this program for the audio component
overlaps that of the OpenSL_playback.c
program given earlier. The structure is very similar. The most notable
difference is that all functions and constants that begin with SL
for OpenSL ES
now begin with XA
for OpenMAX AL.
This program also allows some user interaction to pause/start the playback as well as checking the loudspeaker availability.
The code is
Further examples are given in the OpenMAX AL specification.
There are three implementations that I have been able to access.
The Raspberry Pi has a Broadcom GPU (graphics processing unit) and
Broadcom support OpenMAX IL. The include files needed to build applications
are in /opt/vc/include/IL
, /opt/vc/include
and /opt/vc/include/interface/vcos/pthreads
.
The libraries that need to be linked are in the /opt/vc/lib
directory and are openmaxil
and bcm_host
.
The Broadcom libraries need additional code to be called as well as
standard OpenMAX IL functions. In addition, there are a number of
(legal) extensions to OpenMAX IL that are not found in the specification
or in other implementations. These are described in
/opt/vc/include/IL/OMX_Broadcom.h
.
For these reasons I define RASPBERRY_PI
to allow
these to be dealt with.
The compile line for e.g. listcomponents.c
is
cc -g -DRASPBERRY_PI -I /opt/vc/include/IL -I /opt/vc/include \
-I /opt/vc/include/interface/vcos/pthreads \
-o listcomponents listcomponents.c \
-L /opt/vc/lib -l openmaxil -l bcm_host
The Broadcom implementation is closed source. It appears to be a thin wrapper around their GPU API, and they will not release any details of that API. This means that you cannot extend the set of components, or the codecs supported, since there are no details of how to build new components. While the set of components is reasonable, at present there is no support for codecs other than PCM, and there is no support of non-GPU hardware such as USB soundcards.
OtherCrashOverride says he has managed to get the Broadcom components running under the LIM implementation, but I haven't confirmed that yet.
The Bellagio library does not require additional code or have any extensions.
There are a few minor bugs, so I define BELLAGIO
to handle them.
I built from source, but didn't install, so the includes and libraries
are in a funny place. My compile line is
cc -g -DBELLAGIO -I ../libomxil-bellagio-0.9.3/include/ \
-o listcomponents listcomponents.c \
-L ../libomxil-bellagio-0.9.3/src/.libs -l omxil-bellagio
and at run time
export LD_LIBRARY_PATH=../libomxil-bellagio-0.9.3/src/.libs/
./listcomponents
The Bellagio code is open source.
Downloading the 1.1 version was a hassle because the 1.1 download uses a Git repo that has disappeared (as of Feb, 2013). Instead you have to run
git clone git://limoa.git.sourceforge.net/gitroot/limoa/limoi-components
git clone git://limoa.git.sourceforge.net/gitroot/limoa/limoi-core
git clone git://limoa.git.sourceforge.net/gitroot/limoa/limoi-plugins
git clone git://limoa.git.sourceforge.net/gitroot/limoa/limutil
git clone git://limoa.git.sourceforge.net/gitroot/limoa/manifest
"You have to copy the root.mk in build to a top level folder containing all the code and rename it Makefile. The root.readme file has build instructions." Thanks to OtherCrashOverride for these instructions.
Building the library had some minor hiccups. I had to comment out a couple
of lines from one video file as it referred to non-existent structure fields,
and had to remove -Werrors
from one Makefile.am
as otherwise a warning about an unused variable would abort the compile.
The library build puts files in a new directory in my HOME. I have found some minor bugs in the implementation so far. My compile line is
cc -g -DLIM -I ../../lim-omx-1.1/LIM/limoi-core/include/ \
-o listcomponents listcomponents.c \
-L /home/newmarch/osm-build/lib/ -l limoa -l limoi-core
and at runtime,
export LD_LIBRARY_PATH=/home/newmarch/osm-build/lib/
./listcomponents
The LIM code is open source.
A list of hardware supported versions is at OpenMAX IL Conformant Products .
The OpenMAX IL API is quite distinct from that of OpenMAX AL. The basic concept is of a Component, which is an audio/video (or other) processing unit of some type, such as a volume control, a mixer, an output device. Each Component has zero or more input and output ports, and each port can have one or more buffers that carry data.
OpenMAX IL is typically meant for use by an A/V framework of some kind, such as OpenMAX AL. In addition to OpenMAX AL, there is curently a GStreamer plugin that uses OpenMAX IL underneath. But one can also build standalone applications where direct calls are made into the OpenMAX IL API. Collectively, these are all known as IL clients.
The OpenMAX IL API is difficult to work with directly. Error messages are frequently quite useless and threads will block without explanation until everything is exactly right - and silently blocking doesn't give you any clues about what isn't right. In addition, the examples I have to work with don't follow the specification exactly correctly which can lead to much wasted time.
OpenMAX IL components use buffers to carry data. A component will usually process data from an input buffer and place it on an output buffer. This processing is not visible to the API, and so allows vendors to implement components in hardware or software, built on top of other A/V components, etc. OpenMAX IL gives mechanisms for setting and getting parameters of components, for calling standard functions on the components, or for getting data in and out of components.
While some of the OpenMAX IL calls are synchronous, those that require possibly substantial amounts of processing are asynchronous, communicating the results through callback functions. This leads naturally to a multi-threaded processing model, although OpenMAX IL does not visibly use any thread libraries and should be agnostic to how an IL client uses threads. The Bellagio examples use pthreads while the Broadcom examples for the Raspberry Pi use Broadcom's VideoCore O/S (vcos) threads.
There are two mechanisms for getting data into and out of components. The first is where the IL client makes calls on the component. All components are required to support this mechanism. The second is where a tunnel is set up between two components for data to flow along a shared buffer.
OpenMAX IL in 1.1.2 lists a number of standard components, including (for audio)
a decoder, an encoder, a mixer, a reader, a renderer, a writer,
a capturer and a processor.
An IL client gets such a component by calling OMX_GetHandle()
,
passing in the name of the component. This is a problem: the components
do not have a standard name. The 1.1.2 specification says:
Since components are requested by name, a naming convention is defined. OpenMAX IL component names are zero terminated strings with the following format: “OMX.<vendor_name>.<vendor_specified_convention>”. For example:
OMX.CompanyABC.MP3Decoder.productXYZ
No standardization among component names is dictated across different vendors.
The Bellagio library (you need the source package to see these files) lists in its README only two audio components:
and their names (from the example test files) are "OMX.st.volume.component" and "OMX.st.audio.mixer" respectively. The company behind Bellagio is STMicroelectronics which explains the "st".
The Broadcom OpenMAX IL implementation used on the Raspberry Pi is much better documented. If you download the firmware-master file for the Raspberry Pi it lists the IL components in the documentation/ilcomponents directory. This lists the components audio_capture, audio_decode, audio_encode, audio_lowpower, audio_mixer, audio_processor, audio_render and audio_splitter.
Many of the openMAX IL function calls in the Broadcom examples are buried in Broadcom convenience functions such as
ilclient_create_component(st->client, &st->audio_render,
"audio_render",
ILCLIENT_ENABLE_INPUT_BUFFERS | ILCLIENT_DISABLE_ALL_PORTS);
which wraps around OMX_GetHandle()
. But at least the
ilclient.h
states "Component names as provided are automatically prefixed with
'OMX.broadcom.' before passing to the IL core.". So we can conclude that the real names
are e.g. "OMX.broadcom.audio_render" etc.
There is a simple way of programmatically getting the supported components.
First initialise the OpenMAX system by OMX_init()
and then make calls to OMX_ComponentNameEnum()
.
For successive index values it returns a unique name each time,
until it finally returns an error value of OMX_ErrorNoMore
.
Each component may support a number of roles. These are given by
OMX_GetRolesOfComponent
. The 1.1 specification lists classes
of audio components and associated roles in section 8.6 "Standard Audio
Components". The LIM library matches these, while Bellagio and Broadcom
do not.
The program is listcomponents.c:
The output from the Bellagio library is
Component is OMX.st.clocksrc
Num roles is 1
role: clocksrc
Component is OMX.st.clocksrc
Num roles is 1
role: clocksrc
Component is OMX.st.video.scheduler
Num roles is 1
role: video.scheduler
Component is OMX.st.video.scheduler
Num roles is 1
role: video.scheduler
Component is OMX.st.volume.component
Num roles is 1
role: volume.component
Component is OMX.st.volume.component
Num roles is 1
role: volume.component
Component is OMX.st.audio.mixer
Num roles is 1
role: audio.mixer
Component is OMX.st.audio.mixer
Num roles is 1
role: audio.mixer
Component is OMX.st.clocksrc
Num roles is 1
role: clocksrc
Component is OMX.st.clocksrc
Num roles is 1
role: clocksrc
Component is OMX.st.video.scheduler
Num roles is 1
role: video.scheduler
Component is OMX.st.video.scheduler
Num roles is 1
role: video.scheduler
Component is OMX.st.volume.component
Num roles is 1
role: volume.component
Component is OMX.st.volume.component
Num roles is 1
role: volume.component
Component is OMX.st.audio.mixer
Num roles is 1
role: audio.mixer
Component is OMX.st.audio.mixer
Num roles is 1
role: audio.mixer
No more components
which is not quite correct: the OpenMAX IL specification says that each somponent must appear once only, not repeated.
The Raspberry Pi reports a large number of components but does not define a role for any of them:
Component is OMX.broadcom.audio_capture
Num roles is 0
Component is OMX.broadcom.audio_decode
Num roles is 0
Component is OMX.broadcom.audio_encode
Num roles is 0
Component is OMX.broadcom.audio_render
Num roles is 0
Component is OMX.broadcom.audio_mixer
Num roles is 0
Component is OMX.broadcom.audio_splitter
Num roles is 0
Component is OMX.broadcom.audio_processor
Num roles is 0
Component is OMX.broadcom.camera
Num roles is 0
Component is OMX.broadcom.clock
Num roles is 0
Component is OMX.broadcom.coverage
Num roles is 0
Component is OMX.broadcom.egl_render
Num roles is 0
Component is OMX.broadcom.image_fx
Num roles is 0
Component is OMX.broadcom.image_decode
Num roles is 0
Component is OMX.broadcom.image_encode
Num roles is 0
Component is OMX.broadcom.image_read
Num roles is 0
Component is OMX.broadcom.image_write
Num roles is 0
Component is OMX.broadcom.read_media
Num roles is 0
Component is OMX.broadcom.resize
Num roles is 0
Component is OMX.broadcom.source
Num roles is 0
Component is OMX.broadcom.text_scheduler
Num roles is 0
Component is OMX.broadcom.transition
Num roles is 0
Component is OMX.broadcom.video_decode
Num roles is 0
Component is OMX.broadcom.video_encode
Num roles is 0
Component is OMX.broadcom.video_render
Num roles is 0
Component is OMX.broadcom.video_scheduler
Num roles is 0
Component is OMX.broadcom.video_splitter
Num roles is 0
Component is OMX.broadcom.visualisation
Num roles is 0
Component is OMX.broadcom.write_media
Num roles is 0
Component is OMX.broadcom.write_still
Num roles is 0
No more components
The output from LIM is
Component is OMX.limoi.alsa_sink
Num roles is 1
role: audio_renderer.pcm
Component is OMX.limoi.clock
Num roles is 1
role: clock.binary
Component is OMX.limoi.ffmpeg.decode.audio
Num roles is 8
role: audio_decoder.aac
role: audio_decoder.adpcm
role: audio_decoder.amr
role: audio_decoder.mp3
role: audio_decoder.ogg
role: audio_decoder.pcm
role: audio_decoder.ra
role: audio_decoder.wma
Component is OMX.limoi.ffmpeg.decode.video
Num roles is 7
role: video_decoder.avc
role: video_decoder.h263
role: video_decoder.mjpeg
role: video_decoder.mpeg2
role: video_decoder.mpeg4
role: video_decoder.rv
role: video_decoder.wmv
Component is OMX.limoi.ffmpeg.demux
Num roles is 1
role: container_demuxer.all
Component is OMX.limoi.ffmpeg.encode.audio
Num roles is 2
role: audio_encoder.aac
role: audio_encoder.mp3
Component is OMX.limoi.ffmpeg.encode.video
Num roles is 2
role: video_encoder.h263
role: video_encoder.mpeg4
Component is OMX.limoi.ffmpeg.mux
Num roles is 1
role: container_muxer.all
Component is OMX.limoi.ogg_dec
Num roles is 1
role: audio_decoder_with_framing.ogg
Component is OMX.limoi.sdl.renderer.video
Num roles is 1
role: iv_renderer.yuv.overlay
Component is OMX.limoi.video_scheduler
Num roles is 1
role: video_scheduler.binary
No more components
We will next look at how to get information about the OpenMAX IL
system and any component that we use.
All IL clients must initialise OpenMAX IL by calling OMX_Init()
.
Nearly all functions return error values, and the style used by Bellagio is
err = OMX_Init();
if(err != OMX_ErrorNone) {
fprintf(stderr, "OMX_Init() failed\n", 0);
exit(1);
}
This looks like a reasonable style to me, so I follow it in the sequel.
The next requirement is to get a handle to a component.
This requires the vendor's name for the component,
which can be found using the listcomponents.c
program above. The function OMX_GetHandle
takes some parameters
including a set of callback functions. These are needed to
track behaviour of the application, but are not needed for the example
in this section. This code shows how to get a handle to the Bellagio Volume component:
OMX_HANDLETYPE handle;
OMX_CALLBACKTYPE callbacks;
OMX_ERRORTYPE err;
err = OMX_GetHandle(&handle, "OMX.st.volume.component", NULL /*appPriv */, &callbacks);
if(err != OMX_ErrorNone) {
fprintf(stderr, "OMX_GetHandle failed\n", 0);
exit(1);
}
The component has ports and the ports have channels. Getting and setting
information about these is done by the functions OMX_GetParameter()
,
OMX_SetParameter()
, OMX_GetConfig()
and
OMX_GetConfig()
. The ...Parameter calls are made before the
component is "loaded", ...Config calls are made after it is loaded.
C is not an O/O language and this is an ordinary function call (well, actually
it's a macro). In an O/O language it would be a method of an object taking another
object as parameter as in component.method(object)
.
In OpenMAX IL the Get/Set function takes the calling "object" as first parameter
- the component,
an indicator of what type of "object" the method's parameter is -
an index into possible "object"
types, and a structure for the parameter object.
The index values are related to structures in Table 4-2
"Audio Coding Types by Index" of the 1.1 specification.
The calls take a (pointer to a) structure for filling in or extracting values.
The structures are all normalised so that they share common fields such as the
size of the structure. In Bellagio examples, this is done by a macro setHeader()
.
The structure passed in to get port information is usually a generic structure
of type OMX_PORT_PARAM_TYPE
.
Some fields can be accessed directly; some need a typecast to a more specialised
type; and some buried down in unions and have to be extracted.
Ports are labelled by integer indices. There are different ports for different functions, such as audio, image, video and other. To get information about the starting value for audio ports, use:
setHeader(¶m, sizeof(OMX_PORT_PARAM_TYPE));
err = OMX_GetParameter(handle, OMX_IndexParamAudioInit, ¶m);
if(err != OMX_ErrorNone){
fprintf(stderr, "Error in getting OMX_PORT_PARAM_TYPE parameter\n", 0);
exit(1);
}
printf("Audio ports start on %d\n",
((OMX_PORT_PARAM_TYPE)param).nStartPortNumber);
printf("There are %d open ports\n",
((OMX_PORT_PARAM_TYPE)param).nPorts);
The macro setHeader
justs fills in header information such as version numbers,
and the size of the data structure.
Particular ports may now be queried about their capablilies. We can query for the type of the port (audio or otherwise), the direction (input or output) and information about the MIME type supported.
OMX_PARAM_PORTDEFINITIONTYPE sPortDef;
setHeader(&sPortDef, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
sPortDef.nPortIndex = 0;
err = OMX_GetParameter(handle, OMX_IndexParamPortDefinition, &sPortDef);
if(err != OMX_ErrorNone){
fprintf(stderr, "Error in getting OMX_PORT_PARAM_TYPE parameter\n", 0);
exit(1);
}
if (sPortDef.eDomain == OMX_PortDomainAudio) {
printf("Is an audio port\n");
} else {
printf("Is other device port\n");
}
if (sPortDef.eDir == OMX_DirInput) {
printf("Port is an input port\n");
} else {
printf("Port is an output port\n");
}
/* the Audio Port info is buried in a union format.audio within the struct */
printf("Port min buffers %d, mimetype %s, encoding %d\n",
sPortDef.nBufferCountMin,
sPortDef.format.audio.cMIMEType,
sPortDef.format.audio.eEncoding);
The Bellagio library returns "raw/audio" for the MIME type supported by
its volume control component.
This is not a valid MIME type as listed by
IANA MIME Media Types
, though. The value returned from the encoding is zero,
corresponding to OMX_AUDIO_CodingUnused
which also
does not seem to be correct.
If we try the same program on the Raspberry Pi component audio_render
and on the LIM component OMX.limoi.alsa_sink
we get NULL for the MIME type
but an encoding value of 2 which is OMX_AUDIO_CodingPCM
.
PCM has a MIME type of
audio/L16
so NULL seems inappropriate.
An OpenMAX IL library allows a port to be queried for the data types it supports.
This is done by querying for a OMX_AUDIO_PARAM_PORTFORMATTYPE
object using the index OMX_IndexParamAudioPortFormat
.
According to the specification, for each index from zero upwards
a call to GetParameter()
should return an encoding such as
OMX_AUDIO_CodingPCM
or OMX_AUDIO_CodingMp3
until
there are no more supported formats, on which it returns
OMX_ErrorNoMore
.
The Bellagio code returns a value of OMX_AUDIO_CodingUnused
which is not correct. The LIM code does not set a value at all,
so you just get garbage. The Broadcom implementation works okay,
but as discussed below returns values that are not actually supported.
So there is limited value in this call...
This code tests this:
void getSupportedAudioFormats(int indentLevel, int portNumber) {
OMX_AUDIO_PARAM_PORTFORMATTYPE sAudioPortFormat;
setHeader(&sAudioPortFormat, sizeof(OMX_AUDIO_PARAM_PORTFORMATTYPE));
sAudioPortFormat.nIndex = 0;
sAudioPortFormat.nPortIndex = portNumber;
printf("Supported audio formats are:\n");
for(;;) {
err = OMX_GetParameter(handle, OMX_IndexParamAudioPortFormat, &sAudioPortFormat);
if (err == OMX_ErrorNoMore) {
printf("No more formats supported\n");
return;
}
/* This shouldn't occur, but does with Broadcom library */
if (sAudioPortFormat.eEncoding == OMX_AUDIO_CodingUnused) {
printf("No coding format returned\n");
return;
}
switch (sAudioPortFormat.eEncoding) {
case OMX_AUDIO_CodingPCM:
printf("Supported encoding is PCM\n");
break;
case OMX_AUDIO_CodingVORBIS:
printf("Supported encoding is Ogg Vorbis\n");
break;
case OMX_AUDIO_CodingMP3:
printf("Supported encoding is MP3\n");
break;
#ifdef RASPBERRY_PI
case OMX_AUDIO_CodingFLAC:
printf("Supported encoding is FLAC\n");
break;
case OMX_AUDIO_CodingDDP:
printf("Supported encoding is DDP\n");
break;
case OMX_AUDIO_CodingDTS:
printf("Supported encoding is DTS\n");
break;
case OMX_AUDIO_CodingWMAPRO:
printf("Supported encoding is WMAPRO\n");
break;
#endif
case OMX_AUDIO_CodingAAC:
printf("Supported encoding is AAC\n");
break;
case OMX_AUDIO_CodingWMA:
printf("Supported encoding is WMA\n");
break;
case OMX_AUDIO_CodingRA:
printf("Supported encoding is RA\n");
break;
case OMX_AUDIO_CodingAMR:
printf("Supported encoding is AMR\n");
break;
case OMX_AUDIO_CodingEVRC:
printf("Supported encoding is EVRC\n");
break;
case OMX_AUDIO_CodingG726:
printf("Supported encoding is G726\n");
break;
case OMX_AUDIO_CodingMIDI:
printf("Supported encoding is MIDI\n");
break;
case OMX_AUDIO_CodingATRAC3:
printf("Supported encoding is ATRAC3\n");
break;
case OMX_AUDIO_CodingATRACX:
printf("Supported encoding is ATRACX\n");
break;
case OMX_AUDIO_CodingATRACAAL:
printf("Supported encoding is ATRACAAL\n");
break;
/*
case OMX_AUDIO_Coding:
printf("Supported encoding is \n");
break;
*/
default:
printf("Supported encoding is %d\n",
sAudioPortFormat.eEncoding);
}
sAudioPortFormat.nIndex++;
}
}
Note that the code contains enum values such as OMX_AUDIO_CodingATRAC3
which are specific to the Broadcom library. These are legal values according to an
OpenMAX IL extension mechanism, but of course are not portable values.
The Bellagio library incorrectly returns
OMX_AUDIO_CodingUnused
for every index value.
The Broadcom library can return lots of values. For example, for the
audio_decode
component it returns
Supported audio formats are:
Supported encoding is MP3
Supported encoding is PCM
Supported encoding is AAC
Supported encoding is WMA
Supported encoding is Ogg Vorbis
Supported encoding is RA
Supported encoding is AMR
Supported encoding is EVRC
Supported encoding is G726
Supported encoding is FLAC
Supported encoding is DDP
Supported encoding is DTS
Supported encoding is WMAPRO
Supported encoding is ATRAC3
Supported encoding is ATRACX
Supported encoding is ATRACAAL
Supported encoding is MIDI
No more formats supported
Regrettably, none of these are actually supported except for PCM. According to jamesh in "OMX_AllocateBuffer fails for audio decoder component":
The way it works is that the component passes back success for all the codecs it can potentially support. (i.e. all the codecs we've ever had going). That is then constrained by what codecs are actually installed. It would be better to run time detect which codecs are present, but that code has never been written since its never been required. It's also unlikely ever to be done as Broadcom no longer support audio codecs in this way - they have moved off the Videocore to the host CPU since they are now powerful enough to handle any audio decoding task
That's kind of sad, really.
Putting all the bits together gives the program info.c:
The Makefile for the Bellagio version is
INCLUDES=-I ../libomxil-bellagio-0.9.3/include/
LIBS=-L ../libomxil-bellagio-0.9.3/src/.libs -l omxil-bellagio
CFLAGS = -g
info: info.c
cc $(FLAGS) $(INCLUDES) -o info info.c $(LIBS)
The output using the Bellagio implementation is
Component name: OMX.st.volume.component version 1.1, Spec version 1.1
Audio ports:
Ports start on 0
There are 2 open ports
Port 0 requires 2 buffers
Port 0 is an input port
Port 0 is an audio port
Port mimetype raw/audio
Port encoding is not PCM or MP3 or Vorbis, is 0
Supported audio formats are:
No coding format returned
Port 1 requires 2 buffers
Port 1 is an output port
Port 1 is an audio port
Port mimetype raw/audio
Port encoding is not PCM or MP3 or Vorbis, is 0
Supported audio formats are:
No coding format returned
Video ports:
No ports of this type
Image ports:
No ports of this type
Other ports:
No ports of this type
The Makefile for the Raspberry Pi is
INCLUDES=-I /opt/vc/include/IL -I /opt/vc/include -I /opt/vc/include/interface/vcos/pthreads
CFLAGS=-g -DRASPBERRY_PI
LIBS=-L /opt/vc/lib -l openmaxil -l bcm_host
info: info.c
cc $(CFLAGS) $(INCLUDES) -o info info.c $(LIBS)
The output on the Raspberry Pi for the audio_render component is
Audio ports:
Ports start on 100
There are 1 open ports
Port 100 requires 1 buffers
Port 100 is an input port
Port 100 is an audio port
Port mimetype (null)
Port encoding is PCM
Supported audio formats are:
Supported encoding is PCM
PCM default sampling rate 44100
PCM default bits per sample 16
PCM default number of channels 2
Supported encoding is DDP
No more formats supported
Video ports:
No ports of this type
Image ports:
No ports of this type
Other ports:
No ports of this type
The Makefile for LIM is
INCLUDES=-I ../../lim-omx-1.1/LIM/limoi-core/include/
#LIBS=-L ../../lim-omx-1.1/LIM/limoi-base/src/.libs -l limoi-base
LIBS = -L /home/newmarch/osm-build/lib/ -l limoa -l limoi-core
CFLAGS = -g -DLIM
info: info.c
cc $(CFLAGS) $(INCLUDES) -o info info.c $(LIBS)
The output on LIM for the alsa_sink component is
Component name: OMX.limoi.alsa_sink version 0.0, Spec version 1.1
Audio ports:
Ports start on 0
There are 1 open ports
Port 0 requires 2 buffers
Port 0 is an input port
Port 0 is an audio port
Port mimetype (null)
Port encoding is PCM
LIM doesn't set audio formats properly
Error in getting video OMX_PORT_PARAM_TYPE parameter
Error in getting image OMX_PORT_PARAM_TYPE parameter
Error in getting other OMX_PORT_PARAM_TYPE parameter
The LIM implementation throws errors when the component does not support a mode (here an audio component does not support video, image or other). This is against the 1.1 specification which says
"All standard components shall support the following parameters:
o OMX_IndexParamPortDefinition
o OMX_IndexParamCompBufferSupplier
o OMX_IndexParamAudioInit
o OMX_IndexParamImageInit
o OMX_IndexParamVideoInit
o OMX_IndexParamOtherInit"
I suppose you could argue that an alsa_sink
component isn't
a standard one, so it is allowed. Well, okay...
Playing audio to an output device requires use of an "audio_render" device. This is one of the standard devices in the 1.1 specification, and is included in the Broadcom Raspberry Pi library but not in the Bellagio library. LIM has a component "alsa_sink" which plays the same role.
The structure of a program to play audio is
Note that the Raspberry Pi audio render component will only play PCM data and that the LIM alsa_sink component only plays back at 44,100hz.
Initialising the component is a multi-step process that depends on
the state of the component. Components are created in the
Loaded
state. They transition from one state to another
through an
OMX_SendCommand(handle, OMX_CommandStateSet, <next state>, <param>)
.
The next state from Loaded
should be Idle
and from there to Executing
. There are other states
which we need not be concerned about.
Requests to change state are asynchronous. The send command returns immediately (well, within 5 milliseconds). When the actual change of state occurs an event handler callback function is called.
Some commands require a component to be in a particular state. Requests to put a component into a state are asynchronous. So a request can be made by a client but then the client might have to wait until the state change has occurred. This is best done by the client suspending operation of its thread until woken up by the state change occurring in the event handler.
Linux/Unix has standardised on the Posix pthreads library for managing multiple threads. For our purposes we use two parts from this library: the ability to place a mutex around critical sections, and the ability to suspend/wake up threads based on conditions. Pthreads are covered in many places, with a short and good tutorial by Blaise Barney at POSIX Threads Programming .
The functions and data we use are
pthread_mutex_t mutex;
OMX_STATETYPE currentState = OMX_StateLoaded;
pthread_cond_t stateCond;
void waitFor(OMX_STATETYPE state) {
pthread_mutex_lock(&mutex);
while (currentState != state)
pthread_cond_wait(&stateCond, &mutex);
fprintf(stderr, "Wait successfully completed\n");
pthread_mutex_unlock(&mutex);
}
void wakeUp(OMX_STATETYPE newState) {
pthread_mutex_lock(&mutex);
currentState = newState;
pthread_cond_signal(&stateCond);
pthread_mutex_unlock(&mutex);
}
pthread_mutex_t empty_mutex;
int emptyState = 0;
OMX_BUFFERHEADERTYPE* pEmptyBuffer;
pthread_cond_t emptyStateCond;
void waitForEmpty() {
pthread_mutex_lock(&empty_mutex);
while (emptyState == 1)
pthread_cond_wait(&emptyStateCond, &empty_mutex);
emptyState = 1;
pthread_mutex_unlock(&empty_mutex);
}
void wakeUpEmpty(OMX_BUFFERHEADERTYPE* pBuffer) {
pthread_mutex_lock(&empty_mutex);
emptyState = 0;
pEmptyBuffer = pBuffer;
pthread_cond_signal(&emptyStateCond);
pthread_mutex_unlock(&empty_mutex);
}
void mutex_init() {
int n = pthread_mutex_init(&mutex, NULL);
if ( n != 0) {
fprintf(stderr, "Can't init state mutex\n");
}
n = pthread_mutex_init(&empty_mutex, NULL);
if ( n != 0) {
fprintf(stderr, "Can't init empty mutex\n");
}
}
Hungarian notation was invented by Charles Simonyi to add type or functional information to variable, structure and field names. A form was heavily used in the Microsoft Windows SDK. A simplified form is used in OpenMAX IL by prefixing variables, fields, etc including the following:
The value of such conventions is highly debatable...
There are two types of callback functions relevant to this example: event callbacks which occur on changes of state and some other events, and empty buffer callbacks which occur when a component has emptied an input buffer. These are registered by
OMX_CALLBACKTYPE callbacks = { .EventHandler = cEventHandler,
.EmptyBufferDone = cEmptyBufferDone,
};
err = OMX_GetHandle(&handle, componentName, NULL /*app private data */, &callbacks);
Each component has a number of ports that have to be configured.
The ports are some of the component's resources.
Each port starts off as enabled, but may be set to
disabled by
OMX_SendCommand(handle, OMX_CommandPortDisable, <port number>, NULL)
.
Enabled ports can have buffers allocated for transfer of data
into and out of the component. This can be done in two ways:
OMX_AllocateBuffer
asks the component to perform the
allocation for the client, while with OMX_UseBuffer
the client hands a buffer to the component. As there may be buffer
memory alignment issues, I prefer to let the component do the allocation.
Here is a tricky part. In order to allocate or use buffers on a component,
a request must be made to transition from Loaded
state
to Idle
. So a call to
OMX_SendCommand(handle, OMX_CommandStateSet, OMX_StateIdle, <param>)
.
must be made before buffers are allocated. But the transition
to Idle
will not take place
until each port is either disabled or all buffers
for it are allocated.
This last step cost me nearly a week of head scratching.
The audio_render
component has two ports: an input audio
port and a time update port. While I had configured the audio port
correctly, I had not disabled the time port because I hadn't realised it had one.
Consequently the transition to
Idle
never took place... Code to handle this
is
setHeader(¶m, sizeof(OMX_PORT_PARAM_TYPE));
err = OMX_GetParameter(handle, OMX_IndexParamOtherInit, ¶m);
if(err != OMX_ErrorNone){
fprintf(stderr, "Error in getting OMX_PORT_PARAM_TYPE parameter\n", 0);
exit(1);
}
startPortNumber = ((OMX_PORT_PARAM_TYPE)param).nStartPortNumber;
nPorts = ((OMX_PORT_PARAM_TYPE)param).nPorts;
printf("Other has %d ports\n", nPorts);
/* and disable it */
err = OMX_SendCommand(handle, OMX_CommandPortDisable, startPortNumber, NULL);
if (err != OMX_ErrorNone) {
fprintf(stderr, "Error on setting port to disabled\n");
exit(1);
}
Setting parameters for the audio port is
/** Get audio port information */
setHeader(¶m, sizeof(OMX_PORT_PARAM_TYPE));
err = OMX_GetParameter(handle, OMX_IndexParamAudioInit, ¶m);
if(err != OMX_ErrorNone){
fprintf(stderr, "Error in getting OMX_PORT_PARAM_TYPE parameter\n", 0);
exit(1);
}
startPortNumber = ((OMX_PORT_PARAM_TYPE)param).nStartPortNumber;
nPorts = ((OMX_PORT_PARAM_TYPE)param).nPorts;
if (nPorts > 1) {
fprintf(stderr, "Render device has more than one port\n");
exit(1);
}
setHeader(&sPortDef, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
sPortDef.nPortIndex = startPortNumber;
err = OMX_GetParameter(handle, OMX_IndexParamPortDefinition, &sPortDef);
if(err != OMX_ErrorNone){
fprintf(stderr, "Error in getting OMX_PORT_DEFINITION_TYPE parameter\n", 0);
exit(1);
}
if (sPortDef.eDomain != OMX_PortDomainAudio) {
fprintf(stderr, "Port %d is not an audio port\n", startPortNumber);
exit(1);
}
if (sPortDef.eDir != OMX_DirInput) {
fprintf(stderr, "Port is not an input port\n");
exit(1);
}
if (sPortDef.format.audio.eEncoding == OMX_AUDIO_CodingPCM) {
printf("Port encoding is PCM\n");
} else {
printf("Port has unknown encoding\n");
}
/* create minimum number of buffers for the port */
nBuffers = sPortDef.nBufferCountActual = sPortDef.nBufferCountMin;
printf("Number of bufers is %d\n", nBuffers);
err = OMX_SetParameter(handle, OMX_IndexParamPortDefinition, &sPortDef);
if(err != OMX_ErrorNone){
fprintf(stderr, "Error in setting OMX_PORT_PARAM_TYPE parameter\n", 0);
exit(1);
}
/* call to put state into idle before allocating buffers */
err = OMX_SendCommand(handle, OMX_CommandStateSet, OMX_StateIdle, NULL);
if (err != OMX_ErrorNone) {
fprintf(stderr, "Error on setting state to idle\n");
exit(1);
}
err = OMX_SendCommand(handle, OMX_CommandPortEnable, startPortNumber, NULL);
if (err != OMX_ErrorNone) {
fprintf(stderr, "Error on setting port to enabled\n");
exit(1);
}
nBufferSize = sPortDef.nBufferSize;
printf("%d buffers of size is %d\n", nBuffers, nBufferSize);
inBuffers = malloc(nBuffers * sizeof(OMX_BUFFERHEADERTYPE *));
if (inBuffers == NULL) {
fprintf(stderr, "Can't allocate buffers\n");
exit(1);
}
for (n = 0; n < nBuffers; n++) {
err = OMX_AllocateBuffer(handle, inBuffers+n, startPortNumber, NULL,
nBufferSize);
if (err != OMX_ErrorNone) {
fprintf(stderr, "Error on AllocateBuffer in 1%i\n", err);
exit(1);
}
}
waitFor(OMX_StateIdle);
/* try setting the encoding to PCM mode */
setHeader(&sPCMMode, sizeof(OMX_AUDIO_PARAM_PCMMODETYPE));
sPCMMode.nPortIndex = startPortNumber;
err = OMX_GetParameter(handle, OMX_IndexParamAudioPcm, &sPCMMode);
if(err != OMX_ErrorNone){
printf("PCM mode unsupported\n");
exit(1);
} else {
printf("PCM mode supported\n");
printf("PCM sampling rate %d\n", sPCMMode.nSamplingRate);
printf("PCM nChannels %d\n", sPCMMode.nChannels);
}
OpenMAX has a standard audio render component. But what device does it render to? The inbuilt sound card? A USB sound card? That is not a part of OpenMAX IL - there isn't even a way to list the audio devices - only the audio components.
OpenMAX has an extension mechanism which can be used by an OpenMAX
implementor to answer questions like this. The Broadcom core implementation
has extension types OMX_CONFIG_BRCMAUDIODESTINATIONTYPE
(and OMX_CONFIG_BRCMAUDIOSOURCETYPE
) which can be used
to set the audio destination (source) device. Code to do this is
void setOutputDevice(const char *name) {
int32_t success = -1;
OMX_CONFIG_BRCMAUDIODESTINATIONTYPE arDest;
if (name && strlen(name) < sizeof(arDest.sName)) {
setHeader(&arDest, sizeof(OMX_CONFIG_BRCMAUDIODESTINATIONTYPE));
strcpy((char *)arDest.sName, name);
err = OMX_SetParameter(handle, OMX_IndexConfigBrcmAudioDestination, &arDest);
if (err != OMX_ErrorNone) {
fprintf(stderr, "Error on setting audio destination\n");
exit(1);
}
}
}
Here is where it descends into murkiness again: the header file
<IL/OMX_Broadcom.h> states that the default value of
sName
is "local" but doesn't give any other values.
The Raspberry Pi forums say that this refers to the 3.5mm analog
audio out, and that HDMI is chosen by using the value "hdmi".
No other values are documented, and it seems that the Broadcom OpenMAX IL
does not support any other audio devices: in particular, USB audio
devices are not supported by the current Broadcom OpenMAX IL
components for either input or output. So you can't use
OpenMAX IL for say audio capture on the Raspberry Pi since it
has no Broadcom supported audio input.
Playing the audio file once all the ports are set up consists of filling buffers, waiting for them to empty and then re-filling them until the data is finished. There are two possible styles:
The Bellagio example use the first technique. However, the 1.2 specification says that "...the IL client shall not call IL core or component functions from within an IL callback context" so this is not a good technique. The Raspberry Pi examples use the second technique, but use a non-standard call to find the latency and delay for that time. It is better to just set up more pthreads conditions and block on those.
This leads to a main loop of
emptyState = 1;
for (;;) {
int data_read = read(fd, inBuffers[0]->pBuffer, nBufferSize);
inBuffers[0]->nFilledLen = data_read;
inBuffers[0]->nOffset = 0;
filesize -= data_read;
if (data_read <= 0) {
fprintf(stderr, "In the %s no more input data available\n", __func__);
inBuffers[0]->nFilledLen=0;
inBuffers[0]->nFlags = OMX_BUFFERFLAG_EOS;
bEOS=OMX_TRUE;
err = OMX_EmptyThisBuffer(handle, inBuffers[0]);
break;
}
if(!bEOS) {
fprintf(stderr, "Emptying again buffer %p %d bytes, %d to go\n", inBuffers[0], data_read, filesize);
err = OMX_EmptyThisBuffer(handle, inBuffers[0]);
}else {
fprintf(stderr, "In %s Dropping Empty This buffer to Audio Dec\n", __func__);
}
waitForEmpty();
printf("Waited for empty\n");
}
printf("Buffers emptied\n");
The complete program is
A typical use of an audio system is to play files containing audio data to some output device. Ogg Vorbis is an open, patent free system that defines the Vorbis codec to compress raw data into smaller streams, and the Ogg container format to frame the data and make it easier for applications to manage.
An "Ogg Vorbis" file is an Ogg container of Vorbis encoded data. Playing such a file consists of reading the file, extracting the Vorbis stream from the Ogg frames, decoding the compressed Vorbis stream into, say, a PCM stream and then handing that to some renderer that will play the PCM stream on an output device.
There are no standard OpenMAX IL components to decode Ogg
frame data. The audio_decode
component may
decode a Vorbis stream, but to use that would first require
extracting the Vorbis stream from the Ogg frames.
We consider how to do that in a later section.
The LIM package has a non-standard component
OMX.limoi.ogg_dec
which plays the role
audio_decoder_with_framing.ogg
.
This can directly manage Ogg frames of Vorbis
data, and decode it into a PCM stream.
The OpenMAX IL specification shows in Figure 2.5 that in an "in-context" framework where the component runs in the same thread as the application, then the callback must complete before a call to OMX_FillThis Buffer or to OMX_EmptyThisBuffer returns. So the calback should not make further calls to OMX_FillThis Buffer or to OMX_EmptyThisBuffer or it will just build up a long stack of uncompleted calls. This won't happen if they run in separate threads, so the calls coud be okay.
The Broadcom, LIM and Bellagio packages all use separate threads, and all their examples make re-entrant calls. It's easier to write the code that way. So we follow that, as we don't have any example packages where such calls should not be made.
With those provisos in mind, the code is fairly straightforward:
when an input buffer is emptied, fill it and empty it again,
and when an output buffer is filled, empty it and fill it again.
The program is ogg_decode.c
. it reads from an Ogg
Vorbis file and saves in a PCM file.
We shall use the LIM components and the LIM OpenMAX IL implementation to demonstrate this. There are no appropriate components in the Bellagio or Broadcom cores.
This problem requires the use and interaction
between two components. In this case, it will be the
OMX.limoi.ogg_dec
and the OMX.limoi.alsa_sink
components.
The OMX.limoi.ogg_dec
component will take data from an
Ogg Vorbis stream, extract the Vorbis data and decode it to PCM.
The OMX.limoi.alsa_sink
component can render this PCM
stream to an ALSA output device.
Using the info
program, we can establish the following
characteristics of each component:
OMX.limoi.ogg_dec
Component name: OMX.limoi.ogg_dec version 0.0, Spec version 1.1
Audio ports:
Ports start on 0
There are 2 open ports
Port 0 requires 4 buffers
Port 0 has min buffer size 4096 bytes
Port 0 is an input port
Port 0 is an audio port
Port mimetype (null)
Port encoding is Ogg Vorbis
LIM doesn't set audio formats properly
Port 1 requires 4 buffers
Port 1 has min buffer size 196608 bytes
Port 1 is an output port
Port 1 is an audio port
Port mimetype (null)
Port encoding is PCM
LIM doesn't set audio formats properly
Error in getting video OMX_PORT_PARAM_TYPE parameter
Error in getting image OMX_PORT_PARAM_TYPE parameter
Error in getting other OMX_PORT_PARAM_TYPE parameter
OMX.limoi.alsa_sink
Component name: OMX.limoi.alsa_sink version 0.0, Spec version 1.1
Audio ports:
Ports start on 0
There are 1 open ports
Port 0 requires 2 buffers
Port 0 has min buffer size 32768 bytes
Port 0 is an input port
Port 0 is an audio port
Port mimetype (null)
Port encoding is PCM
LIM doesn't set audio formats properly
Error in getting video OMX_PORT_PARAM_TYPE parameter
Error in getting image OMX_PORT_PARAM_TYPE parameter
Error in getting other OMX_PORT_PARAM_TYPE parameter
The decoder has a minimum of four input and four output buffers. The renderer only requires two input buffers, and of course has no output buffers. We will need to take the output from the decoder buffers and put them into the renderer's input buffers. It isn't totally clear to me whether or not you are required to use all of the buffers, but you can add extra buffers. It would be easier coding if we had the same number of buffers at each stage!
Should this be an aside? If you look at the LIM component
"OMX.limoi.ffmpeg.decode.video" it has a minimum of 64 buffers.
But if you look at the example LIM code
limoi-core/test/decode.c
you see the following:
port_def.nBufferCountActual = 2;
port_def.nBufferCountMin = 2;
port_def.nBufferSize = bytes;
OMX_SetParameter(comp, OMX_IndexParamPortDefinition, &port_def);
Now this is not correct! The 1.1 specification in section <IP_ADDRESS>.1 says
nBufferCountMin
is a read-only [emphasis added] field that specifies the minimum number of buffers that the port requires. The component shall define this non-zero default value.
nBufferSize
is a read-only [emphasis added] field that specifies the minimum size in bytes for buffers that are allocated for this port.
and this example resets these read-only fields.
So what I've done is to make the number of buffers configurable by a #define and set this number in all of the components ports.
The callback logic I use is
Thus the decoder output and renderer input buffers are linked by the IL client, while the decoder input buffer is emptied by the decoder component independently. In an earlier version I tried to link all three buffers, but this always eventually deadlocked with a decoder input buffer not emptying properly.
The code is play_ogg.c
The Khronos group has produced specifications for audio and video in low capability systems. These are currently used by Android and by the Raspberry Pi. This chapter has given an introductory overview of these specifications and some example programs and will be expanded later.


License Plate Transcription using Object Detection (Part 2)
14 Apr 2020Last week we looked into the basic functionality of the TensorFlow Object Detection API. We ran our object detection model to transcribe license plates. This week, we’ll look into some of the options available to us during the training process. Next, we’ll build some OpenCV logic to order the detections, creating a meaningful number. Finally, deployment will be the name of the game. We’ll create a simple web application to serve up our model.
Ordering our detections
If you run the driver program from last week, you’ll notice that the detections are ordered by the confidence of each bounding box. While this is useful for understanding which letters our model is most accurate on, it does not reflect the order of the characters present on the license plate. So, how do we fix this?
Let’s take a look at one of our license plates.
We have access to the (x,y) coordinates of each bounding box. Thus, we sort the detections in the ascending order of x-coordinates. This becomes our license plate number! Making some modifications to our driver code, and running it.
Looks good!
Ordering with Multiple Lines
I wish it were that simple. Sure, the code works for the above license plate. But it only works because all the characters present in the license plate are aligned along only one line. What happens if the content is divided into two lines?
This particular scenario is not common, but it does present an interesting edge case challenge to our ‘out of the box’ solution. The next bit is a bit technical in case you’d like to skip the details. It isn’t particularly important.
Our first order of business is to detect how many lines of characters are present. License plates typically do not contain more than two lines. Thus our goal is to detect how many lines are present, and which line each character belongs to. Once we know which line each character belongs to, we sort the characters present on each line in ascending orders of their x-coordinates. Finally, we concatenate the characters present on the first line with that of the second line.
Which Character is on Which Line?
Here’s what we know. Once we sort each detection by their y-coordinate, we can say for sure that the first element will be on the first line. We also know that the last element will be on the last line. Whether this ‘last line’ is the first line or the second line remains to be seen. So, we draw a horizontal line through the midpoint of the first element. Next, we draw a horizontal line through the midpoint of the last element. If the distance between the two horizontal lines is greater than a particular threshold, then we know that the first character on the license plate and the last character on the license plate are separated by a considerable gap. This means that the first and last character is on two separate lines. If the distance between the two horizontal lines is lesser than a particular threshold, then odds are, it’s on a single line.
Sorting Each Line
Whether there’s one line or two, once we know which line each character belongs to, we sort the line in ascending order of x-coordinates. Assuming there’s one, we now have the transcribed number plate! If there’s two, we sort the first line. Then, we sort the second line. Finally, we append the sorted detections from the second line to the sorted detections from the first line. You can write your own script to automate this and output this information into a more useful format such as a CSV file. Given here (Yet to be uploaded) is the modified driver program.
Deployment
Render is a brilliant service that allows you to host your containerized applications on the cloud, allowing executable access to anyone to access your project! By the end of this, we’ll be able to upload an image and view the license plate number on the website. So how do we package our application so that all our dependencies are available? The answer, is that we create an isolated environment for our application so that it can run independently on any system or service. Docker is the magic word. Docker allows us to neatly package our code into a container, which can later be run through a Render web service. Thus we will be creating a simple web application.
Containerization
Let’s go ahead and set up Docker on our system. Installation instructions are provided here. The key step is to create a Dockerfile. What is a Dockerfile? It consists of instructions that the container runs to ensure that the application encased can run properly. We specify the instructions that are needed to run our application within the container. For this particular application, here is my Dockerfile:
Let’s go ahead and build and run the container.
For an explanation of the respective commands used, take a look at the Docker documentation.
Next, go ahead and create your own repository on GitHub. Upload the Dockerfile as well as the required files to the repo. Next, create an account on Render, and link the repo. Everything should be up and running! Given below is a screenshot of our page!
I won’t go into the creation of the webpage itself, as it delves too much into HTML, CSS, and JS. I have uploaded the page onto the repo where you can pick up a copy.
Of course, I can’t actually host the webpage at all times as the service costs $7 a month. I will explore Heroku’s a free option at a later date. Note that we will probably have to switch to a lighter model such as SSD MobileNet as the service only allows for 512MB of RAM + ROM.


--- layout: default ---
SmallK is a high performance software package for low rank matrix approximation via the nonnegative matrix factorization (NMF). NMF is a low-rank approximation where a matrix is approximated by a product of two nonnegative factors. The role of NMF in data analytics has been as significant as the singular value decomposition (SVD). However, due to nonnegativity constaints, NMF has far superior interpretability of its results for many practical problems such as image processing, chemometrics, bioinformatics, topic modeling for text analytics and many more. Our approach to solving the NMF nonconvex optimization problem has proven convergence properties and is one of the most efficient methods developed to date.
This work was funded in part by the DARPA XDATA program under contract FA8750-12-2-0309. Our DARPA program manager is Mr. Wade Shen and our XDATA Principal Investigator is Prof. Haesun Park of the Georgia Institute of Technology.
SmallK is under copyright by the Georgia Institute of Technology, 2014. All source code is released under the Apache 2.0 license.


Toggle navigation
Our Journal
Home
About
Search
Contribute
First post!
Posted on January 4, 2015
This is my first post, how exciting!
← Previous Post
Next Post →
Please enable JavaScript to view the
comments powered by Disqus.


F
Sign Up
First Name
Last Name
ID:
Password:
Show Password
Birthday:
Security Question
What is your first teacher's name?
What is your mother's birth place?
Who is your favorite actor, musician, or artist?
In what city or town did your mother and father meet?
What is your maternal grandmother's maiden name?
In what city or town was your first job?
Ans:
Gender
Male
Female
Sign Up


| Name | Date | Time |
|---|---|---|
| Pick up milk | Today | 8:00 PM |
| Get a car wash | ||
| Do homework | Today |
event
event
event
| Name | Date | Time |
|---|---|---|
| Don't forget to pack | 3/12/17 | 8:00 PM |
| Pick up kids at 4 | 3/29/17 | 9:00 PM |
| Taxes due | 3/30/17 | 11:59 PM |


By Ryan M. Hoffman | 2016-11-01
Should You Even Develop for Mobile?
In a word, yes. Mobile development is growing to be more and more important every single year. Every day people spend more time on their phones, tablets and other mobile devices. As of June 2016 there are over 2.2 million apps available in the Play Store and over 2 million in the App Store. This article from back in 2015 says that the average American spends 4.7 hours per day on their phone! That’s nearly a third of our waking hours each day! If you want some of that screen time to be dedicated to your app then you better think very carefully about what type of app you want to deliver to your users. So what will it be, native or cross-platform?
The Case for Native Apps
Native apps, generally speaking, offer a better experience when compared to a similarly developed cross-platform app. This isn’t always true, and it definitely doesn’t mean that you should only choose to launch native apps. These are a few reasons why you should consider going native.
Native apps are designed to be platform specific, so they feel more comfortable for the user. This is incredibly important because 77% of users will delete your app within 72 hours of downloading it. That number will only go up if the design is not familiar and comfortable for your users. On Android, Google have created Material Design as the standard. Most of the popular apps in the Play Store have already shifted to conform to this style, and it has become normal for Android users. On iOS, Apple have their own design guidelines that is different from Material Design. There are certain navigation patterns that are different and other animations and visual queues that might mean something different on each platform. By developing a native app for each os you can bring the little things from the design standards out and make your app easier and more enjoyable for your users.
Another big bonus for native apps is the increased performance you get from them. When developing for Android, an app written in Java will almost always be faster than one developed in Javascript or some other web language. The same goes for iOS apps written in Swift or Objective-C; they will almost always be faster than their cross-platform counterparts. This is because the APIs are developed in the native language by Google or Apple. Usually cross-platform apps are developed using Javascript or a language that compiles to Javascript, and the large libraries and other code can end up running much slower on the phone or tablet than well developed native code.
Certain hardware related features like gestures, multi-touch, and various other sensor related components like GPS, accelerometer and gyroscope are simpler to access and use in native apps. Most of the time there are very straight forward APIs or libraries that allow access to these components. These are more advanced functionalities and might not be necessary in all apps, but it is important to keep in mind when deciding what is right for you and your idea.
The Case for Cross-Platform
Cross-platform apps are easier to create and can cut down your development time significantly. The main selling point here is that you have a single code base to maintain for all users on all operating systems. The idea here is that you create one app, which is then optimized and packaged properly for each platform and published in each marketplace.
After reading the section about native apps and seeing all the features and speed you might be thinking that’s the way to go, but I challenge you to think about this. You have an idea for an app, maybe you have a website and you want to take it a step further and turn it into a full on app. You already have the website to maintain, all the code that goes along with it, and the headaches from hosting it. Now you decide to make apps for Android and iOS. Maybe you are a code ninja and already know Java and Swift, so that saves you time and money because you don’t have to learn new technology or hire a freelancer to do it for you. But you start writing the iOS app first and after a couple weeks it is ready to publish, but you don’t want to launch it without the Android app also. So you sit down and bang out that app in a couple more weeks. Now both are ready to go so you submit them to their respective app stores. The good news is they look great and are blazing fast, but now every time you want to make a change to your website you have three different apps in three different code bases to maintain and update. Then a few of your crazy followers get the new Windows phone and are still on the mobile version of your site because no app exists for them. What now?
Now contrast this with a cross-platform app. You can use most if not all of your existing Javascript from your website when creating the app. Once development is complete you can optimize the code for each platform and publish to each app store. Every time you want to make a change to your website you can make the changes to the app code also and everything will look great and up to date across all platforms. If you have users with Windows Phone or Firefox OS or anything else you can use the same code to publish to their app stores and have good looking apps for them too.
So what’s the catch? What you gain in simplicity you will lose in functionality. There may be a trade off in speed as well although I doubt it if you are simply converting a website into a web app. The biggest drawback will be trying to implement new features and meet the design standards of each platform.
Which Is Right For You?
This is a question that you are going to have to answer for yourself. If your idea is something small and simple like converting your website into an app then cross-platform might be the way to go for you. Other things like tip calculators and simple note taking apps usually have simple UI’s and are good candidates for cross-platform apps. More complex apps that rely on sensors in the phone or things like multi-touch are probably better off as native apps.
At the end of the day you need to evaluate your business or your idea and decide which choice is right for you. Making a list of required features is a great way to see exactly what will be involved in development and will probably make the decision much easier for you. Remember that there is no “right” answer and even if you start out with a simple cross-platform app you can always scale up to a native app and update from there. Good luck and happy developing!


I recently graduated from a Front-End Web Development course at General Assembly where I learned HTML, CSS, JavaScript, and jQuery and how to be an awesome Front End Developer! During my spare time, I enjoy learning, being on my laptop in bookstores and coffee shops and spending time with my French Bulldog Brooklyn.
Developed a multi-column layout blog, landing page, and contact forms that render on mobile devices.
Used a design team's wireframes to develop this company's responsive homepage.
Built web app prototype that allows users to store and quickly retrieve photos using keywords.


Students
Name:
{{ students.name }}
Photo:
Grade:
{{ students.grade }}
School:
{{ students.school }}
Teacher:
{{ students.teacher }}
Place an image URL here:


Home
Appliances
Clothes
Automobiles
Cables
Switches
Contacts
0
items - $
0
switches
scale your network
explore
total
$
0
clear cart
checkout
our
Ethernet switches
all
Both 24 and 48 port POE is available using 802.3af class 3 with 370 Watt power capacity. Dual-purpose uplinks for Gigabit Ethernet uplink flexibility, allowing use of either a copper or a fiber uplink. A dual-purpose uplink port has one 10/100/1000 Ethernet port and one Small Form-Factor Pluggable (SFP)-based Gigabit Ethernet port, with one port active at a time
Cisco Catalyst 2960-24TT-L V02
$
23
The DGS-1008P is an 8 port Gigabit Desktop switch with 4 PoE ports. It provides a cost-effective way for SOHO and SMB to benefit from the Power over Ethernet technology by allowing users to power up devices such as wireless Access Points, network cameras or IP phones directly from the network cables. Its fanless design makes it completely silent so it is ideal for offices, libraries or meeting rooms.
DGS-1008P
$
78
Is the next generation of enterprise-class standalone and stackable access-layer switches that provide the foundation for full convergence between wired and wireless on a single platform. The 3650 Series is built on the advanced Cisco StackWise®-160, and takes advantage of the new Cisco Unified Access™ Data Plane (UADP) application-specific integrated circuit (ASIC).
Cisco Catalyst 3650-24PD-S
$
250
provides capabilities that ideally suited to support the convergence of wired and wireless access. The new Cisco Unified Access Data™ Plane (UADP) (ASIC) powers the switch and enables uniform wired-wireless policy enforcement, application visibility, flexibility, and application optimization.
Cisco Catalyst 3650-48FD-S
$
400
The Extralink Euros PoE Switch can automatically detect and supply power to IEEE 802.3af compliant devices. It has 4 10/100 Mbps Auto-Negotiation RJ45 ports with PoE out. A compact and cheap switch to power access points and cameras.
Extralink Euros 4-Port 10/100Mbps Unmanaged PoE
$
45
The Cloud Router Switch 106-1C-5S is a desktop size smart switch, equipped with one Gigabit Ethernet / SFP combo port and five 1.25Gbps SFP cages.The package includes a power supply. Powered by a 400MHz CPU and 128MB RAM, it runs RouterOS with a L5 license and supports 11- 30V power.
Mikrotik CRS106-1C-5S
$
80


Why Data Viz?
We're not naturally equipped to deal with numbers
Data vizualization allows us to "see" the data using existing facilities: shape, area, volume, color, orientation, etc
Data vizualization is a communication technique, not an artistic expressions
Data Viz today
D3.js dominates the landscape (for good reasons ?)
Mosly charts - Still rare to see interactions and transitions
Effective data vizualization requires an aggregation of various techniques: web dev, 2D/3D graphics, data analysis
Opportunities?
Wanna try?
I recommend starting with D3.js
Play around with the [examples](https://bl.ocks.org/mbostock)
D3.js is mostly functional programming, so familiarity with the paradigm helps
Understand the data join ENTER UPDATE EXIT contract!
What else?
Data scrapping helps. I use Clojure with Enlive library
Understanding statistics allows you to tell a story with data
Avoid misleading your readers


> Dates With Eights MUSIC
When I wrote this song, I had just been on a date with a really good looking girl, hence the eight (she was really more of a nine, but that doesn't rhyme as well). I took some inspiration from the song Allein by Pryda. My favorite part about this song is the combination of a classical house, "four-on-the-floor" type of beat, combined with some triplet rhythms in the middle. That pumping of the synths is caused by a technique called sidechaining. Basically, the audio from the kick drum compresses the sound of the synths, so everytime the kick drum hits, the synths are affected. Normally, this effect coincides with the typical four-on-the-floor beat used by a lot of dance music. I switched it up a little in this song to try and give it a bit more groove. Enjoy!


About this Survey
This survey is about construction noise in Singapore and consists of four parts:
- Part 1: About you. We ask a few questions about you.
- Part 2: Your choices. We ask you to choose between different types of construction noise.
- Part 3: Hearing acuity test. We will play several sounds to understand your sensitivity to sounds.
- Part 4: About you. We ask a few more questions about you.


Any fool can use a computer. Many do.
I'm one of them, in the form of a backend developer. You'll read some gibberish like CI pipelines, bounded contexts, "sources of truth", and so on. Get ready.
I'm one of them, in the form of a backend developer. You'll read some gibberish like CI pipelines, bounded contexts, "sources of truth", and so on. Get ready.


is a 2015 action role-playing game developed and published by CD Projekt. Based on The Witcher series of fantasy novels by Polish author Andrzej Sapkowski, it is the sequel to the 2011 game The Witcher 2: Assassins of Kings. Played in an open world with a third-person perspective, players control protagonist Geralt of Rivia, a monster hunter known as a witcher, who is looking for his missing adopted daughter on the run from the Wild Hunt: an otherworldly force determined to capture and use her powers. Players battle the game's many dangers with weapons and magic, interact with non-player characters, and complete main-story and side quests to acquire experience points and gold, which are used to increase Geralt's abilities and purchase equipment. Its central story has several endings, determined by the player's choices at certain points in the game.
is an action role-playing game developed and published by Capcom. A part of the Monster Hunter series, it was released worldwide for PlayStation 4 and Xbox One in January 2018, with a Microsoft Windows version in August 2018. In the game, the player takes the role of a Hunter, tasked to hunt down and either kill or trap monsters that roam in one of several environmental spaces. If successful, the player is rewarded through loot consisting of parts from the monster and other elements that are used to craft weapons and armor, amongst other equipment. The game's core loop has the player crafting appropriate gear to be able to hunt down more difficult monsters, which in turn provide parts that lead to more powerful gear. Players may hunt alone, or can hunt in cooperative groups of up to four players via the game's online services.
is an action role-playing video game developed by FromSoftware. "As fires fade and the world falls into ruin, journey into a universe filled with more colossal enemies and environments. Players will be immersed into a world of epic atmosphere and darkness through faster gameplay and amplified combat intensity. Fans and newcomers alike will get lost in the game hallmark rewarding gameplay and immersive graphics. Now only embers remain… Prepare yourself once more and Embrace The Darkness!"
is an action role-playing game developed by PlatinumGames and published by Square Enix."Humanity has been driven from the Earth by mechanical beings from another world. In a final effort to take back the planet, the human resistance sends a force of android soldiers to destroy the invaders. Now, a war between machines and androids rages on... A war that could soon unveil a long-forgotten truth of the world."


GBP/JPY Technical Analysis: 200-bar SMA guards immediate downside
by Anil Panchal- GBP/JPY bounces off monthly low amid oversold RSI conditions.
- A one-week-old falling trend line gains buyers’ attention during further recovery.
The GBP/JPY pair recovers from 200-bar SMA while trading around 139.65 during Monday morning in Asia.
The quote’s the recent pullback, amid oversold conditions of 14-bar Relative Strength Index (RSI), shifts bull’s attention to a downward sloping resistance line since November 18, at 140.67 now. However, a sustained clearance of 140.00 round-figure will be necessary for that.
In a case, prices move successfully beyond the near-term key resistance line, monthly to surrounding 141.60 will return to charts.
On the downside, pair’s declines below 200-bar Simple Moving Average (SMA) level of 139.46 can take rest on 23.6% Fibonacci Retracement of October-November upside, at 138.95.
Should there be bearish formation around 138.95, sellers can target October 11 high near 137.90 during further declines.
GBP/JPY 4-hour chart
Trend: Further recovery likely
additional important levels
| Overview | |
|---|---|
| Today last price | 139.67 |
| Today Daily Change | 22 pips |
| Today Daily Change % | 0.16% |
| Today daily open | 139.45 |
| Trends | |
|---|---|
| Daily SMA20 | 140.09 |
| Daily SMA50 | 137.28 |
| Daily SMA100 | 134.43 |
| Daily SMA200 | 138.47 |
| Levels | |
|---|---|
| Previous Daily High | 140.52 |
| Previous Daily Low | 139.32 |
| Previous Weekly High | 141.58 |
| Previous Weekly Low | 139.32 |
| Previous Monthly High | 141.51 |
| Previous Monthly Low | 130.42 |
| Daily Fibonacci 38.2% | 139.78 |
| Daily Fibonacci 61.8% | 140.06 |
| Daily Pivot Point S1 | 139.01 |
| Daily Pivot Point S2 | 138.56 |
| Daily Pivot Point S3 | 137.81 |
| Daily Pivot Point R1 | 140.21 |
| Daily Pivot Point R2 | 140.96 |
| Daily Pivot Point R3 | 141.41 |


| MPI_REDUCE_SCATTER_BLOCK( sendbuf, recvbuf, recvcount, datatype, op, comm) | |
| IN sendbuf | starting address of send buffer (choice) |
| OUT recvbuf | starting address of receive buffer (choice) |
| IN recvcount | element count per block (non-negative integer) |
| IN datatype | data type of elements of send and receive buffers (handle) |
| IN op | operation (handle) |
| IN comm | communicator (handle) |
int MPI_Reduce_scatter_block(const void* sendbuf, void* recvbuf, int recvcount, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)
MPI_Reduce_scatter_block(sendbuf, recvbuf, recvcount, datatype, op, comm, ierror)
TYPE(*), DIMENSION(..), INTENT(IN) :: sendbuf
TYPE(*), DIMENSION(..) :: recvbuf
INTEGER, INTENT(IN) :: recvcount
TYPE(MPI_Datatype), INTENT(IN) :: datatype
TYPE(MPI_Op), INTENT(IN) :: op
TYPE(MPI_Comm), INTENT(IN) :: comm
INTEGER, OPTIONAL, INTENT(OUT) :: ierror
MPI_REDUCE_SCATTER_BLOCK(SENDBUF, RECVBUF, RECVCOUNT, DATATYPE, OP, COMM, IERROR)
<type> SENDBUF(*), RECVBUF(*)
INTEGER RECVCOUNT, DATATYPE, OP, COMM, IERROR
If comm is an intracommunicator, MPI_REDUCE_SCATTER_BLOCK first performs a global, element-wise reduction on vectors of count = n*recvcount elements in the send buffers defined by sendbuf, count and datatype, using the operation op, where n is the number of processes in the group of comm. The routine is called by all group members using the same arguments for recvcount, datatype, op and comm. The resulting vector is treated as n consecutive blocks of recvcount elements that are scattered to the processes of the group. The i-th block is sent to process i and stored in the receive buffer defined by recvbuf, recvcount, and datatype.
Advice
to implementors.
The MPI_REDUCE_SCATTER_BLOCK routine is functionally equivalent to:
an MPI_REDUCE collective operation with count equal to recvcount* n,
followed by an MPI_SCATTER with sendcount equal to recvcount.
However, a direct implementation may run faster.
( End of advice to implementors.)
The ``in place'' option for intracommunicators is specified by passing MPI_IN_PLACE
in the sendbuf argument on all processes.
In this case, the input data is taken from the receive buffer.
If comm is an intercommunicator, then the result of the reduction of the data provided by processes in one group (group A) is scattered among processes in the other group (group B) and vice versa. Within each group, all processes provide the same value for the recvcount argument, and provide input vectors of count = n*recvcount elements stored in the send buffers, where n is the size of the group. The number of elements count must be the same for the two groups. The resulting vector from the other group is scattered in blocks of recvcount elements among the processes in the group.
Rationale.
The last restriction is needed so that the length of the send buffer of one group can be
determined by the local recvcount argument of the other group.
Otherwise, a communication is needed to figure out how many elements are reduced.
( End of rationale.)


Emirates announces US$16 billion order for 50 Airbus A350 planes
DUBAI: Dubai state-owned airline Emirates said on Monday it had placed a firm order for 50 Airbus A350 jets worth US$16 billion at list prices.
"Together with the A380, the A350 will give us more capacity and flexibility. We will be able to expand to new markets with these aircraft," Emirates Chief Executive Officer Ahmed bin Saeed Al Maktoum said at the Dubai Airshow.
The deal signed at the show marked a final and amended version of a tentative deal for 40 A330neo aircraft and 30 A350 jets, which has been pending since the start of the year.
"The new aircrafts are less noisy and provide us with a lower carbon footprint," Al Maktoum said, adding that he expected the first A350 jets' delivery in 2023.
The world's top jetmakers have been trying to win final approval for more than US$30 billion in orders from Emirates on ice for up to two years as the airline complains about manufacturing delays and performance issues.
Airbus Chief Executive Officer Guillaume Faury said: "This order is a very strong endorsement of the A350 planes with the latest technology."
Emirates, however, said it was no longer considering the A330neo at this stage.
Faury said: "I don't know what it means for A330 for Emirates. But the A330 remains relevant for others. Customers from different regions are supportive of new orders for this aircraft."
Emirates said it was still in negotiations with Boeing on the fate of a provisional order for 40 of the U.S. planemaker's 787 Dreamliners.
(Reporting by Tim Hepher and Ankit Ajmera; Writing by Tuqa Khalid; Editing by Louise Heavens and Andrew Cawthorne)


Allow Pakatan to complete full term, Maszlee tells Tanjung Piai voters
by Ben TanPONTIAN, Nov 9 — Education Minister Maszlee Malik said it is unfair for voters in Tanjung Piai to punish the Pakatan Harapan (PH) administration, as they have only been governing the country for less than two years.
He urged for patience as the ruling government, including his ministry, had initiated many positive plans to improve people’s wellbeing.
“If they are not satisfied with PH’s performance, then Barisan Nasional (BN) that helmed the country for more than 60 years also proved that they could not administer the country well,” said Maszlee.
He said this after attending a dialogue session with non-governmental organisations at a seafood restaurant in Kukup Laut here today.
Maszlee, who is also the Simpang Renggam MP, said voters should give the PH administration a chance to complete the full term of five years and said the coalition can do better than the 60 years under BN.
“To me, the voters in Tanjung Piai can think maturely and can judge ... the previous government is known for their corruption and kleptocracy.
“Our prime minister is committed despite being 94-years-old and he works hard to make Malaysia the Asian Tiger,” said Maszlee referring to the country’s planned path to being developed and economically strong.
He stressed that choosing a PH candidate would strengthen the government’s position to bring in more development.


Bulldawg Beds
Student housing for students by students!
Location
North
South
East
West
Beds
1
2
3
4
Date
Fall
Spring
Summer
Price
$0-399
$400-599
$600-799
$800+


Preparation time
less than 30 mins
Cooking time
10 to 30 mins
Serves
Serves 4
Preheat the oven to 180C/350F/Gas 4.
Heat one teaspoon of the oil in a deep-sided, heavy-based ovenproof, lidded pan over a medium heat. When the oil is hot, add the chorizo and fry for 1-2 minutes, stirring regularly, or until crisp on both sides. Pour in the sherry and continue to cook until the liquid has evaporated, then remove the chorizo from the pan using a slotted spoon and set aside to drain on kitchen paper.
Add the remaining teaspoon of oil to the same pan, then add the onion and garlic and fry for 4-5 minutes, or until softened.
Add the canned tomatoes and paprika, stir well to combine, then continue to cook for a further 4-5 minutes.
Return the cooked chorizo to the pan along with the peas, beans, cooked chickpeas and fish stock. Stir well to combine, then season, to taste, with salt and freshly ground black pepper.
Place the hake steaks on top of the mixture in the pan. Cover the pan with a lid, then transfer the pan to the oven and cook for 10-12 minutes, or until the hake is cooked through.
When the hake is cooked through, squeeze over the lemon juice and sprinkle over the chopped parsley.
To serve, place one hake steak onto each of four serving plates. Spoon the chickpea and vegetable mixture alongside. Serve with crusty bread.


Out of the Dorm Room
Founded in early 2017 by a group of engineering students out of forms at MIT, Princeton University, Olin College and Cornell University, we began as a hacker-maker project to build a drone to hunt invasive lionfish. As the team accelerated its development, however, it realized that the scope of the problem and the magnitude of its devastation required more than a hobbyist effort to have an impact. It was out of that realization that AMRC grew until a tech startup, still committed to its original social mission, but now equipped with the resources and energy of an early stage tech startup. What was originally an exercise in hardware hacking had grown into a commitment to leverage everything a scrappy but driven team of young engineers had to offer.
Guiding Principles
We are to our core a values-driven organization. In our work, we are guided by a handful–but a salient handful–of driving principles:
Rethinking Problem Domains
In pursuing a niche–and in the view of this team, neglected–problem, we hold strongly the view that our industry has far too frequently misprioritized its talents and resources to relatively insignificant problems. While a team of fresh college grads might not be the one to prove them wrong, we’ll certainly try: we intend to provide a positive example of bringing high tech to real problems, and hopefully do our part in redirecting the energies and resources of our nation’s best and brightest to domains taht really matter.
Democratizing the World of High Technology
Certainly reaching beyond the breadth of the wide-eyed new grads that comprise the team, but also certainly dear to our mission as a team is the belief that most communities in America have not received their fair share of the joys and wonders of the tech revolution. Indeed, with tech talent increasingly concentrated in a handful of cities around the country, the dynamics and populations, talent, and reward have led to an inefficient and unjust distribution of access to education and employment, especially in the fields that are the fastest growing. At AMRC, we hope to do our part in attracting the very highest caliber of talent to Pensacola to build great technology and grow alongside the community that we have come–very rapidly–to cherish.
Responsible Engineering and Product Lifecycle
At AMRC we take extreme care to ensure that the technologies that we develop, however effective, are only applied to productive causes. Seeing far too many risks and past instances of abuse of emerging technologies, we consider ourselves fully responsible for the usage of our technology and as such, commit ourselves to designing safe systems with zero collateral impact on our reefs and oceans, all while guaranteeing that our technology will only be used by honest, ethical partners.
Team
Ian Switzer
Ian specializes in both robotics and hardware development. Though he has extensive knowledge in typical electrical engineer skills such as digital circuit design, PCB design/inhouse manufacturing, and FPGA/microcontroller usage he is also very well versed in mechanical design/CAD, computer programming, and embedded firmware development. Ian attributes this knowledge to the dozens of projects he has pursued in which he designed and built a wide range of devices including but not limited to rapidly and autonomously recharging drones, autonomous weaponized robots, and an intelligent high load power distribution board. Ian has also demonstrated extreme competency in 3D printer technology and usage.
Taylor Njaka
Taylor specializes in underwater robotics, and has had experience with computer and general electronic hardware, as well as advanced control systems. In his undergraduate career, he designed and fabricated an inexpensive ocean wave energy generator using extensive MATLAB optimization for maximum power output and cost analysis. He was recently the project lead on novel type of ROV omnidirectional propulsion system designed w/ helicopter based controls for MIT’s Marine Robotics Team. He also has experience with ocean wave gliders and other forms of marine propulsion, and is a former FRC Robotics world champion.
Duncan Michael
Duncan attended high school on the Big Island of Hawai’i where learned to scuba dive and became an avid spear fisherman. For the past four years he has attended Olin College of Engineering in Needham, Massachusetts where he has designed and built drones, medical devices, and off-road race cars, in addition to over 70 other group and personal projects. He specializes in advanced mechanical design computer aided design for manufacturing. He has applied his expertise to all design projects at AMRC. In addition to his product design and manufacturing, Duncan builds test rigs in order to validate design decisions and improve said designs.
Yuan Wang
Yuan is a product manager and mathematician hailing from Los Angeles, California, serving as a software engineer for AMRC. He has worked at data modeling, software engineering, and product management capacities at high powered firms in aerospace, computer vision, and the hedge fund industry. During his undergraduate years at Princeton University, Yuan served as President of the Princeton University Cycling Team, led student startups in digital health and thin client application streaming, served as a mentor at top college hackathons, and volunteered with a number of organizations working in causes ranging from global poverty to homelessness in LA to cancer research.
William Betrand
Will is a software engineer with extensive experience in rapid prototyping and computer vision currently contributing to AMRC’s work in artificial intelligence and computer vision. At Princeton University, Will was a varsity cross country and track runner and led a number of student-used applications, as well cloud streaming software.
Ethan Gordon
Ethan is an electrical engineer hailing from Chicago, IL contributing a strong theoretical background in electrical engineering and physics. At Princeton, Ethan graduated with highest honors from the Electrical Engineering department and was a strong contributor on a wide range of academic academic research.