Chapter 5. Transcoders

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 dmSDK transcoder device consists of the following:

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 which provides two things: a way for your application to send buffers containing bits to be processed, and a way to send empty buffers to hold the results of that processing.

Finding a Suitable Transcoder

Use dmGetCapabilites(3dm) to obtain details of all transcoders on the system.

Opening a Logical Transcoder

Open a transcoder in much the same way as a path, but using dmOpen(3dm):

DMstatus dmOpen (DMint64 xcodeId, DMpv* options, DMopenid* 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.

Controlling the Transcoder

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 the DM_IMAGE_CODING is UNCOMPRESSED on the source and DVCPRO_50 on the destination, then you are requesting the transcoder to:

  • Take uncompressed data from the source pipe.

  • Apply a DVCPRO_50 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 DM_SELECT_ID parameter, which directs all following controls to a particular ID (in this case, the ID of a pipe on the transcoder).

For example, here is code to set image width and height on both the source and destinations pipes:

Example 5-1. Set Image Width/Height on Pipes

msg[0].param = DM_SELECT_ID_INT64;
msg[0].value.int64 = DM_XCODE_SRC_PIPE;
msg[1].param = DM_IMAGE_WIDTH_INT32;
msg[1].value.int32 = 1920;
msg[2].param = DM_IMAGE_HEIGHT_INT32;
msg[2].value.int32 = 1080;
msg[3].param = DM_SELECT_ID_INT64;
msg[3].value.int64 = dm_XCODE_DST_PIPE;
msg[4].param = DM_IMAGE_WIDTH_INT32;
msg[4].value.int32 = 1920;
msg[5].param = DM_IMAGE_HEIGHT_INT32;
msg[5].value.int32 = 1280;
msg[6].param = DM_END;

dmSetControls(someOpenXcode, msg);

Sending Buffers

Once the controls on a pipe have been set, you may begin to send buffers to it for processing. Do this with the dmSendBuffers(3dm) call.

Call dmSendBuffers 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.

For example, here is 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 = DM_SELECT_ID_INT64;
msg[0].value.int64 = DM_XCODE_SRC_PIPE;
msg[1].value.pByte = srcBuffer;
msg[1].length = srcImageSize;
msg[2].param = DM_SELECT_ID_INT64;
msg[2].value.int64 = DM_XCODE_DST_PIPE;
msg[3].value.pByte = dstBuffers;
msg[3].maxLength = dstImageSize;
msg[4].param = DM_END;

dmSendBuffer(someOpenXcode, msg);

Starting a Transfer

The sendBuffers call places buffer messages on a pipe queue to the device. You must then call dmBeginTransfer(3dm) to tell the transcoder engine to start processing messages.

Note: The beginTransfer call may fail if the source and destination pipe settings are inconsistent.

Changing Controls During a Transfer

During a transfer, you could attempt to change controls by using dmSetControls(3dm), but this is often undesirable since 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 dmSendControls(3dm) call as on a path, again using DM_SELECT_ID to direct particular controls to a particular pipe.

Note: Parameter changes sent with sendControls are guaranteed to only affect buffers sent with subsequent send calls.

Note: 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:


Transcoder was unable to process data.

Receiving a Reply Message

Whenever you pass buffer pointers to the transcoder (by calling sendBuffers) 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 dmReceiveMessage(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 which parallelize across multiple physical processors.

Ending Transfers

To end a transfer, call dmEndTransfer(3dm). This is a blocking call which:

  • 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 endTransfer before beginTransfer 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.

Closing a Transcoder

When your application has finished using a transcoder it may close it, see dmClose(3dm) :

DMstatus dmClose( DMopenId openId);

This causes an implicit EndTransfer. It then frees any resources used by the device.

Work Functions

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 dmXcodeWork(3dm) function.

If you open a software transcoder while setting the DM_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 dmXcodeWork(3dm) function.

Note: This only applies to software transcoders, and only if you set the DM_XCODE_MODE_SYNCHRONOUS option when opening the transcoder.

Multi-Stream Transcoders

This chapter has described the operation of a single-stream transcoder (one in which all controls/buffers can be sent to the transcoder engine using the DM_SELECT_ID parameter). Some transcoders, however, particularly those which need to consume source and destination buffers at different rates, will not work efficiently with this programming model. For those cases, it is possible to access each transcoder pipe individually, sending/receiving buffers on the source pipe at a different rate than on the destination pipe. This will be supported in a future revision of the dmSDK.