A transcoder provides a means to process data in memory. Support for transcoders may be implemented entirely in software, or it may be performed with hardware assistance. In either case, the software interfaces are consistent.
Each ML transcoder device consists of the following:
A transcoder engine that performs the actual processing
A number of source pipes and destination pipes
The engine takes data from buffers in the source pipes, processes it, and stores the result in buffers in the destination pipes. Each pipe acts much like a path that provides two things:
A way for your application to send buffers containing bits to be processed
A way to send empty buffers to hold the results of that processing
This chapter discusses the following:
Use mlGetCapabilities(3dm) to obtain details of all transcoders on the system:
MLstatus mlGetCapabilities(MLint64 objectId, MLpv** capabilities); |
where:
objectId is the 64-bit identifier for the object whose capabilities are being queried
capabilities is a pointer to the head of the resulting capabilities list
Open a transcoder in much the same way as a path, but using mlOpen(3dm):
MLstatus mlOpen (MLint64 xcodeId, MLpv* options, MLopenid* openid); |
When a transcoder is opened, it creates any required source and destination pipes. Just as for a path, an open transcoder is a logical entity -- as such, a single physical device may support several transcoders simultaneously.
The transcoder engine is controlled indirectly through the source and destination pipes:
Controls on the source pipe describe what you will be sending the transcoder for input
Controls on the destination pipe describe the results you want
The difference between the source and destination controls dictates what operations the transcoder should perform.
For example, if ML_IMAGE_COMPRESSION_INT32 is ML_COMPRESSION_UNCOMPRESSED on the source and ML_COMPRESSION_DVCPRO50_525 on the destination, then you are requesting the transcoder to do the following:
Take uncompressed data from the source pipe
Apply a ML_COMPRESSION_DVCPRO50_525 compression
Write the results to the destination pipe
To set controls on a transcoder, construct a controls message as you would for a video path. The only difference is that you must explicitly direct controls to a particular pipe. This is done through the ML_SELECT_ID parameter, which directs all following controls to a particular ID (in this case, the ID of a pipe on the transcoder).
Example 5-1 shows code to set the image width and height on both the source and destinations pipes.
Example 5-1. Set Image Width/Height on Pipes
msg[0].param = ML_SELECT_ID_INT64; msg[0].value.int64 = ML_XCODE_SRC_PIPE; msg[1].param = ML_IMAGE_WIDTH_INT32; msg[1].value.int32 = 1920; msg[2].param = ML_IMAGE_HEIGHT_INT32; msg[2].value.int32 = 1080; msg[3].param = ML_SELECT_ID_INT64; msg[3].value.int64 = ML_XCODE_DST_PIPE; msg[4].param = ML_IMAGE_WIDTH_INT32; msg[4].value.int32 = 1920; msg[5].param = ML_IMAGE_HEIGHT_INT32; msg[5].value.int32 = 1280; msg[6].param = ML_END; mlSetControls(someOpenXcode, msg); |
After the controls on a pipe have been set, you may begin to send buffers to it for processing. Do this with the mlSendBuffers(3dm) call:
MLstatus mlSendBuffers(MLopenid openid, MLpv* buffers); |
where:
openid is a previously-opened digital media object
buffers is a list of parameter/value (MLpv) pairs
Call mlSendBuffers once for all the buffers corresponding to a single instant in time. For example, if the transcoder expects both an image buffer and an audio buffer, you must send both in a single sendBuffers call.
Example 5-2 shows code to send a source buffer to the source pipe and a destination buffer to the destination pipe.
Example 5-2. Send Source/Destination Buffers to Source/Destination Pipes
msg[0].param = ML_SELECT_ID_INT64; msg[0].value.int64 = ML_XCODE_SRC_PIPE; msg[1].param = ML_IMAGE_BUFFER_POINTER; msg[1].value.pByte = srcBuffer; msg[1].length = srcImageSize; msg[2].param = ML_SELECT_ID_INT64; msg[2].value.int64 = ML_XCODE_DST_PIPE; msg[3].param = ML_IMAGE_BUFFER_POINTER; msg[3].value.pByte = dstBuffers; msg[3].maxLength = dstImageSize; msg[4].param = ML_END; mlSendBuffers(someOpenXcode, msg); |
The mlSendBuffers call places buffer messages on a pipe queue to the device. You must then call mlBeginTransfer (3dm) to tell the transcoder engine to start processing messages.
![]() | Note: The mlBeginTransfer call may fail if the source and destination pipe settings are inconsistent. |
During a transfer, you could attempt to change controls by using mlSetControls(3dm), but this is often undesirable because the effect of the control change on buffers currently being processed is undefined. A better method is to send control changes in the same queue as the buffer messages. Do this with the same mlSendControls(3dm) call as on a path, again using ML_SELECT_ID to direct particular controls to a particular pipe.
![]() | Note: Parameter changes sent with mlSendControls are guaranteed to only affect buffers sent with subsequent send calls. |
Some hardware transcoders may be unable to accommodate control changes during a transfer. If in doubt, examine the capabilities of particular parameter to determine if it may be changed while a transfer is in progress.
In a transcoder, it is possible to get the following exception event:
ML_EVENT_XCODE_FAILED | |
Transcoder was unable to process data. |
Whenever you pass buffer pointers to the transcoder by calling mlSendBuffers , you give up all rights to that memory until the transcoder has finished using it. As the transcoder finishes processing each buffers message, it will enqueue a reply message back to your application. You may read these reply messages in exactly the same way as on a path by calling mlReceiveMessage(3dm).
The transcoder queue maintains a strict first-in, first-out ordering. If buffer A is sent before buffer B, then the reply to A will come before the reply to B. This is guaranteed even on transcoders that parallelize across multiple physical processors.
To end a transfer, call mlEndTransfer(3dm). This is a blocking call that does the following:
Allows all buffers currently in the engine to complete
Marks any remaining messages as aborted
By examining the reply to each message, your application can determine whether or not it was successfully processed.
It is also acceptable to call mlEndTransfer before mlBeginTransfer has been called. In that case, any messages in the queue are aborted and returned to the application.
![]() | Note: If you are not interested in the result of any pending buffers, you can simply close the transcoder without bothering to first end the transfer. |
When your application has finished using a transcoder it may close it:
MLstatus mlClose( MLopenId openId); |
This causes an implicit mlEndTransfer. It then frees any resources used by the device.
See the mlClose(3dm) man page.
In most cases, the difference between hardware and software transcoders is transparent to an application. Software transcoders may have more options and may run more slowly, but for many applications these differences are not significant.
One notable difference between hardware and software transcoders is that software transcoders will attempt to use as much of the available processor time as possible. This may be undesirable for some applications. To counter this, an application has the option to do the work of the transcoder itself, in its own thread. This is achieved with the mlXcodeWork (3dm) function.
If you open a software transcoder while setting the ML_XCODE_MODE_SYNCHRONOUS option, the transcoder will not spawn any threads and will not do any processing on its own. To perform a unit of transcoding work, your application must now call the mlXcodeWork(3dm) function.
![]() | Note: This only applies to software transcoders, and only if you set the ML_XCODE_MODE_SYNCHRONOUS option when opening the transcoder. |