Updated: October 28, 2024 |
You can use the OpenMAX AL media engine to decode an audio stream to a QNX buffer queue. You can then read the data items from the buffer queue, further process them if desired, and send them to the output.
In the following example, we create a media player and provide it with an audio file URL for the data source and a QNX buffer queue for the audio data sink. To start decoding, we start playback through the media player. We then use the XAQNXBufferQueueSinkItf interface to read the decoded audio data in buffers, and copy the data to an output file. When we've finished reading and copying a preset number of bytes, we stop playback.
typedef struct omxal_objs { /* Object Interfaces */ XAObjectItf engine_decode; XAObjectItf player; XAPlayItf player_itf; /* Buffer queue interfaces */ XAQNXBufferQueueSinkItf decoder_bufferq_out_itf; } omxal_objs_t;
omxal_objs_t omxal_objs = {0}; /* Create the engine and store its reference in the engine_decode field of our oxmal_objs_t structure */ XAresult res = xaCreateEngine( &(omxal_objs->engine_decode), num_opts, engine_opts, // We don't need any interfaces, so we // don't define these other parameters 0, NULL, NULL ); if (res != XA_RESULT_SUCCESS) { /* Error-handling code goes here */ }
Using the newly written engine_decode field in the omxal_objs object, we realize the engine in synchronous mode and get the engine interface and store a reference to it (in engine_decode_itf). For information about the required API calls, see the Realize() and GetInterface() descriptions in the OpenMAX AL specification.
XADataLocator_URI uri = { XA_DATALOCATOR_URI, in_path }; XADataSource audio_src = { (void *)&uri, NULL }; XADataLocator_QNXBufferQueue buffer_queue_out = { XA_DATALOCATOR_QNXBUFFERQUEUE, BUFFER_COUNT; }; XADataSink audio_snk = { (void *)&buffer_queue_out, NULL };
/* Use the engine interface to create the media player */ res = (*engine_decode_itf)->CreateMediaPlayer( engine_decode_itf, &(omxal_objs->player), &audio_src, NULL, &audio_snk, NULL, ...);
Using the newly written player field of the omxal_objs object, we realize the player in synchronous mode and get the interfaces for the player and the player's audio output, which we store in the player_itf and decoder_bufferq_out_itf fields. (This entails calling Realize() and GetInterface() as before.)
XADataFormat_QNXEncoded audio_info; XAQNXBufferQueueSinkItf *decoder_bufferq_out_itf = &omxal_objs->decoder_bufferq_out_itf; XAresult res = (**decoder_bufferq_out_itf)->GetFormat( *decoder_bufferq_out_itf, audio_info );
res = (*(omxal_objs->player_itf))->SetPlayState( omxal_objs->player_itf, XA_PLAYSTATE_PLAYING );
/* Grab 2s of data */ int bytes_to_write = audio_info.audio_info.sampleRate / 1000 * audio_info.audio_info.channels * audio_info.audio_info.bitsPerSample / 8 * 2; unsigned char *write_buf; if ( (write_buf = malloc( bytes_to_write ) ) == NULL ) { /* Error-handling code goes here */ }
/* Keep track of how many bytes we've read from the audio source and written to the output buffer so we don't exceed the limit */ int bytes_written = 0; while ( bytes_written < bytes_to_write ) { XAQNXBuffer *buffer = (**decoder_bufferq_out_itf)->GetAndWait( *decoder_bufferq_out_itf, NULL ); if (buffer) { if ( (buffer->pBufferData) && (buffer->dataSize > 0) ) { /* Calculate the number of bytes to copy */ int tocopy; if (bytes_written + buffer->dataSize > bytes_to_write) { tocopy = bytes_to_write - bytes_written; } else { tocopy = buffer->dataSize; } /* Do the copy and update our running totals */ memcpy( write_buf, buffer->pBufferData, tocopy ); buffer->dataUsed = buffer->dataSize; bytes_written += tocopy; write_buf += tocopy; } } /* Return the buffer memory because we're finished with it */ if ( (**decoder_bufferq_out_itf)->Done( *decoder_bufferq_out_itf, buffer ) != XA_RESULT_SUCCESS ) { /* Error-handling code goes here */ } } }
int outputfd = open( out_path, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR ); if (outputfd == -1) { /* Error-handling code goes here */ } if ( write( outputfd, write_buf, bytes_written ) == -1 ) { /* Error-handling code goes here */ } close( outputfd ); free( write_buf );
(*(omxal_objs->player_itf))->SetPlayState( omxal_objs->player_itf, XA_PLAYSTATE_STOPPED );We then need to clean up the OpenMAX AL interfaces by calling Destroy() for each of the player and engine_decode fields in the omxal_objs object (for details, see the OpenMAX AL specification).