After the C-code has been generated, we test it with the original MATLAB testbench to ensure functional equivalence of the resulting C-code. To facilitate this process, Catalytic MCS has a feature to compile and link the generated C-code into a MATLAB function. This feature uses MATLAB's standard MEX API, which enables MATLAB functions to call functions written in other programming languages.
In this example, MCS replaces the original vscalerrgb.m file with a form of the C code compiled for MEX. This compiled code is called vscalerrgb.dll. We can now test the compiled code by simply calling the existing MATLAB testbench (test_vscaler.m). Our testbench now calls vscalerrgb.dll instead of vscalerrgb.m. This enables us to verify that the generated C-code behaves identically to the original algorithm without changing the testbench.
Step 5: Integrate C-code
We are now confident that the generated C-code is functionally identical to the source MATLAB code. The last step is to integrate it with the C-code for the rest of the application.
The video decoding application makes use of the DirectShow API. In a DirectShow application, a number of "filters" are linked together to implement the steps in decoding and displaying video:
- Reading the source file
- Separating the audio and video streams
- Decoding the MPEG video stream
- Rendering the video frames.
DirectShow coordinates the interaction between filters and imposes a consistent memory management policy. Microsoft designed DirectShow specifically to allow easy incorporation of custom filters.
For this application, we create a custom filter to implement the vertical scaling algorithm. We start by deriving a filter from CTransformFilter, a C++ base class supplied by DirectShow. The CTransformFilter provides a way to access and modify samples in a media stream; in this context, a "sample" represents individual frames in a video stream. Frames are integer arrays, with each pixel represented by a 3-byte RGB tuple. Recall that vscalerrgb expects three integer matrices, representing R, G, and B values; the output of vscalerrgb has a similar format. In order to integrate vscalerrgb with the DirectShow application, we must implement a simple wrapper to translate the image frame as it passes in and out of vscalerrgb; the wrapper does nothing more than "demux" input frames into separate R, G, and B arrays just prior to entering vscalerrgb. The reverse operation is performed at the output of vscalerrgb.
It is worth noting that MATLAB stores 2-D matrices in column-major order. In other words, a column vector in MATLAB is stored as contiguous elements in memory. C, on the other hand, uses row-major ordering: a row vector is stored as contiguous elements in memory. This discrepancy in representation could lead to confusion whenever the orientation of 2-D data is critical to the application. Fortunately, MCS has the option to handle row-major data by generating code to transpose matrices as they pass in and out of MCS-generated C code. Thus, even though our MATLAB function operates on column-major data, we don't have to worry about manually transposing matrices in our C implementation.
In addition, MATLAB functions typically allocate memory for output variables dynamically, and MCS follows this convention. By default, MCS-generated code will allocate memory for the output R, G, and B matrices within vscalerrgb.c. We need to deallocate this memory in our wrapper code. Note that MCS also supports a directive, CATALYTIC_pass_by_ref(), which allows the user to pass pre-allocated output arrays into the MATLAB function. In some cases, this mode of function interface may be more appropriate for integration with other C code.
At this point, we can run our video decoding application and successfully demonstrate real-time vertical scaling of a video.
(Click to enlarge)
Figure 5 The CatalyticMCS filter in a DirectShow graph
Benefits
Automating a manual process has the immediate benefit of shortening design time. But automatically generating C-code from MATLAB has many more advantages for algorithm developers. They can continue to work in their preferred environment and generate reference models of their algorithm on demand. The generated C-code can be easily verified for correctness with the original MATLAB testbench. Algorithm execution is not limited to the MATLAB environment, but can now be run on any platform with an ANSI C compiler.
About the authors
Niraj Shah is a product marketing manager at Catalytic Inc. He recently received a Ph.D. in electrical engineering and computer sciences from the University of California at Berkeley. His research focused on programming models for application-specific processors. Previously, Niraj was a venture partner at ITU Ventures, an early-stage venture capital firm investing in companies emerging from leading research institutions. He can be reached at [email protected].
Robert Yu is an applications engineer at Catalytic Inc. Before joining Catalytic, he held software development and management positions at a variety of Silicon Valley companies. During this time, his work focused on signal processing and telecommunications applications. Robert holds bachelor's and master's degrees in electrical engineering from Cornell. He can be reached at [email protected].