Пример #1
0
/*----------------------------------------------------------------------
|    CrossFader_Activate
+---------------------------------------------------------------------*/
BLT_METHOD
CrossFader_Activate(BLT_MediaNodeInstance* instance, BLT_Stream* stream)
{
    ATX_Properties settings;
    CrossFader*    fader = (CrossFader*)instance;

    /* stop listening for settings on the current stream, if any */
    if (!ATX_OBJECT_IS_NULL(&fader->context) &&
        fader->listener_handle != NULL) {
        if (BLT_SUCCEEDED(BLT_Core_GetSettings(&fader->base.core, 
                                               &settings))) {
            ATX_Properties_RemoveListener(&settings, fader->listener_handle);
        }
        fader->listener_handle = NULL;
    }

    /* keep a reference to the stream */
    fader->context = *stream;

    /* listen to settings on the new stream */
    if (BLT_SUCCEEDED(BLT_Core_GetSettings(&fader->base.core, 
                                            &settings))) {
        ATX_PropertyListener me;
        ATX_INSTANCE(&me)  = (ATX_PropertyListenerInstance*)fader;
        ATX_INTERFACE(&me) = &CrossFader_ATX_PropertyListenerInterface;
        ATX_Properties_AddListener(&settings, 
                                    "SomeSetting",
                                    &me,
                                    &fader->listener_handle);
    }

    return BLT_SUCCESS;
}
Пример #2
0
/*----------------------------------------------------------------------
|    BLT_Decoder_PumpPacketWithOptions
+---------------------------------------------------------------------*/
BLT_Result
BLT_Decoder_PumpPacketWithOptions(BLT_Decoder* decoder, BLT_Flags options)
{
    BLT_Result result;

    /* check if we're in non-blocking mode */
    if (options & BLT_DECODER_PUMP_OPTION_NON_BLOCKING) {
        if (decoder->output) {
            BLT_OutputNodeStatus status;
            result = BLT_OutputNode_GetStatus(decoder->output, &status);
            if (BLT_SUCCEEDED(result) && (status.flags & BLT_OUTPUT_NODE_STATUS_QUEUE_FULL)) {
                ATX_LOG_FINE("output queue full, would block");
                
                /* ensure that the stream is not paused */
                BLT_Stream_Start(decoder->stream);
                
                return BLT_ERROR_WOULD_BLOCK;
            }
        }
    }

    /* pump a packet */
    result = BLT_Stream_PumpPacket(decoder->stream);
    if (BLT_FAILED(result)) return result;

    return BLT_SUCCESS;
}
Пример #3
0
/*----------------------------------------------------------------------
|    BLT_Decoder_GetVolume
+---------------------------------------------------------------------*/
BLT_Result
BLT_Decoder_GetVolume(BLT_Decoder* decoder, float* volume)
{
    BLT_MediaNode* output_node;
    BLT_Result     result;
    
    /* check parameters */
    if (volume == NULL) return BLT_ERROR_INVALID_PARAMETERS;
    
    /* default value */
    *volume = 0.0f;
    
    /* get the volume from the output node */
    result = BLT_Stream_GetOutputNode(decoder->stream, &output_node);
    if (BLT_SUCCEEDED(result) && output_node) {
        BLT_VolumeControl* volume_control = ATX_CAST(output_node, BLT_VolumeControl);
        if (volume_control) {
            result = BLT_VolumeControl_GetVolume(volume_control, volume);
        } else {
            result = BLT_ERROR_NOT_SUPPORTED;
        }
        ATX_RELEASE_OBJECT(output_node);
    } else {
        result = BLT_ERROR_INVALID_STATE;
    }
    
    return result;
}
Пример #4
0
/*----------------------------------------------------------------------
|   Mp4Parser_SetupAudioOutput
+---------------------------------------------------------------------*/
static BLT_Result
Mp4Parser_SetupAudioOutput(Mp4Parser* self, AP4_Movie* movie)
{
    ATX_Properties* properties = NULL;
    
    // select the audio track
    if (BLT_SUCCEEDED(BLT_Stream_GetProperties(ATX_BASE(self, BLT_BaseMediaNode).context, &properties))) {
        ATX_PropertyValue value;
        bool selector_is_strict = false;
        if (ATX_SUCCEEDED(ATX_Properties_GetProperty(properties, 
                                                     BLT_STREAM_AUDIO_TRACK_SELECTOR_STRICT_PROPERTY, 
                                                     &value))) {
            if (value.type == ATX_PROPERTY_VALUE_TYPE_BOOLEAN) {
                selector_is_strict = value.data.boolean == ATX_TRUE;
            }
        }
        if (ATX_SUCCEEDED(ATX_Properties_GetProperty(properties, 
                                                     BLT_STREAM_AUDIO_TRACK_SELECTOR_INDEX_PROPERTY, 
                                                     &value))) {
            if (value.type == ATX_PROPERTY_VALUE_TYPE_INTEGER) {
                ATX_LOG_INFO_1("selecting audio track by index (%d)", value.data.integer);
                self->audio_output.track = movie->GetTrack(AP4_Track::TYPE_AUDIO, value.data.integer);
                if (self->audio_output.track == NULL) {
                    ATX_LOG_INFO("track not found");
                    if (selector_is_strict) return BLT_SUCCESS;
                }
            }
        } else if (ATX_SUCCEEDED(ATX_Properties_GetProperty(properties, 
                                                            BLT_STREAM_AUDIO_TRACK_SELECTOR_ID_PROPERTY, 
                                                            &value))) {
            if (value.type == ATX_PROPERTY_VALUE_TYPE_INTEGER) {
                ATX_LOG_INFO_1("selecting audio track by ID (%d)", value.data.integer);
                self->audio_output.track = movie->GetTrack((AP4_UI32)value.data.integer);
                if (self->audio_output.track == NULL) {
                    ATX_LOG_INFO("track not found");
                    if (selector_is_strict) return BLT_SUCCESS;
                } else if (self->audio_output.track->GetType() != AP4_Track::TYPE_AUDIO) {
                    ATX_LOG_INFO("track is not audio");
                    if (selector_is_strict) return BLT_SUCCESS;
                } 
            }
        }
    }
    
    // select the first audio track if no specific track was selected
    if (self->audio_output.track == NULL) {
        ATX_LOG_INFO("selecting first audio track");
        self->audio_output.track = movie->GetTrack(AP4_Track::TYPE_AUDIO);
    }
    
    // exit now if the track does not exist
    if (self->audio_output.track == NULL) return BLT_SUCCESS;

    ATX_LOG_INFO_1("found audio track (id=%d)", self->audio_output.track->GetId());
    
    // use the first sample description by default
    return Mp4ParserOutput_SetSampleDescription(&self->audio_output, 0);
}
/*----------------------------------------------------------------------
|    BLT_DecoderServer::OnSetOutputCommand
+---------------------------------------------------------------------*/
void
BLT_DecoderServer::OnSetOutputCommand(BLT_CString name, BLT_CString type)
{
    BLT_Result result;

    ATX_LOG_FINE_2("set output (%s / %s",
                   BLT_SAFE_STRING(name), BLT_SAFE_STRING(type));
    result = BLT_Decoder_SetOutput(m_Decoder, name, type);
    if (BLT_SUCCEEDED(result)) {
        // notify of the new volume
        float volume=0.0f;
        result = BLT_Decoder_GetVolume(m_Decoder, &volume);
        if (BLT_SUCCEEDED(result)) {
            m_Client->PostMessage(new BLT_DecoderClient_VolumeNotificationMessage(volume));
        }
        result = BLT_SUCCESS;
    }
    SendReply(BLT_DecoderServer_Message::COMMAND_ID_SET_OUTPUT, result);
}
/*----------------------------------------------------------------------
|    BLT_DecoderServer::WaitForTerminateMessage
+---------------------------------------------------------------------*/
void
BLT_DecoderServer::WaitForTerminateMessage()
{
    BLT_Result result;
    do {
        result = m_MessageQueue->PumpMessage(NPT_TIMEOUT_INFINITE);
    } while (BLT_SUCCEEDED(result));

    SetState(STATE_TERMINATED);
}
Пример #7
0
/*----------------------------------------------------------------------
|    BLT_Decoder_UpdateStatus
+---------------------------------------------------------------------*/
static BLT_Result
BLT_Decoder_UpdateStatus(BLT_Decoder* decoder) 
{
    BLT_StreamStatus status;
    BLT_StreamInfo   stream_info;
    BLT_Result       result;

    result = BLT_Stream_GetStatus(decoder->stream, &status);
    if (BLT_SUCCEEDED(result)) {
        decoder->status.time_stamp = status.time_stamp;
        decoder->status.position   = status.position;
    }

    result = BLT_Stream_GetInfo(decoder->stream, &stream_info);
    if (BLT_SUCCEEDED(result)) {
        decoder->status.stream_info = stream_info;
    }

    return BLT_SUCCESS;
}
/*----------------------------------------------------------------------
|    BLT_DecoderServer::SendReply
+---------------------------------------------------------------------*/
BLT_Result 
BLT_DecoderServer::SendReply(BLT_DecoderServer_Message::CommandId id, 
                             BLT_Result                           result)
{
    BLT_DecoderClient_Message* reply;

    if (BLT_SUCCEEDED(result)) {
        reply = new BLT_DecoderClient_AckNotificationMessage(id);
    } else {
        reply = new BLT_DecoderClient_NackNotificationMessage(id, result);
    }

    return m_Client->PostMessage(reply);
}
/*----------------------------------------------------------------------
|    BLT_DecoderServer::OnSeekToTimeCommand
+---------------------------------------------------------------------*/
void
BLT_DecoderServer::OnSeekToTimeCommand(BLT_UInt64 time)
{
    BLT_Result result;
    ATX_LOG_FINE_1("[%d]", (int)time);
    result = BLT_Decoder_SeekToTime(m_Decoder, time);
    if (BLT_SUCCEEDED(result)) {
        UpdateStatus();

        // update the state we were in the STATE_EOS state
        if (m_State == STATE_EOS) SetState(STATE_STOPPED);
    }

    SendReply(BLT_DecoderServer_Message::COMMAND_ID_SEEK_TO_TIME, result);
}
/*----------------------------------------------------------------------
|    BLT_DecoderServer::OnSeekToPositionCommnand
+---------------------------------------------------------------------*/
void
BLT_DecoderServer::OnSeekToPositionCommand(BLT_UInt64 offset, BLT_UInt64 range)
{
    BLT_Result result;
    ATX_LOG_FINE_2("[%d:%d]", (int)offset, (int)range);
    result = BLT_Decoder_SeekToPosition(m_Decoder, offset, range);
    if (BLT_SUCCEEDED(result)) {
        UpdateStatus();

        // update the state we were in the STATE_EOS state
        if (m_State == STATE_EOS) SetState(STATE_STOPPED);
    }

    SendReply(BLT_DecoderServer_Message::COMMAND_ID_SEEK_TO_POSITION, result);
}
Пример #11
0
/*----------------------------------------------------------------------
|    CrossFader_Deactivate
+---------------------------------------------------------------------*/
BLT_METHOD
CrossFader_Deactivate(BLT_MediaNodeInstance* instance)
{
    ATX_Properties settings;
    CrossFader*    fader = (CrossFader*)instance;

    /* remove our listener */
    if (BLT_SUCCEEDED(BLT_Core_GetSettings(&fader->base.core, 
                                            &settings))) {
        ATX_Properties_RemoveListener(&settings, 
                                        &fader->listener_handle);
    }

    /* we're detached from the stream */
    ATX_CLEAR_OBJECT(&fader->context);

    return BLT_SUCCESS;
}
Пример #12
0
/*----------------------------------------------------------------------
|    BLT_Decoder_SetOutputNode
+---------------------------------------------------------------------*/
BLT_Result
BLT_Decoder_SetOutputNode(BLT_Decoder*   decoder, 
                          BLT_CString    name,
                          BLT_MediaNode* node)
{
    BLT_Result result;
    
    /* clear the status */
    BLT_Decoder_ClearStatus(decoder);

    /* set the input of the stream */
    result = BLT_Stream_SetOutputNode(decoder->stream, name, node);
    if (BLT_SUCCEEDED(result)) {
        BLT_Decoder_OutputChanged(decoder, node);
    }

    return result;
}
Пример #13
0
/*----------------------------------------------------------------------
|   DcfParser_Construct
+---------------------------------------------------------------------*/
static void
DcfParser_Construct(DcfParser* self, BLT_Module* module, BLT_Core* core)
{
    /* construct the inherited object */
    BLT_BaseMediaNode_Construct(&ATX_BASE(self, BLT_BaseMediaNode), module, core);

    /* construct the members */
    DcfParserInput_Construct(&self->input, module);
    DcfParserOutput_Construct(&self->output);
    
    /* look for a key manager */
    ATX_Properties* properties = NULL;
    if (BLT_SUCCEEDED(BLT_Core_GetProperties(core, &properties))) {
        ATX_PropertyValue value;
        if (ATX_SUCCEEDED(ATX_Properties_GetProperty(properties, 
                                                     BLT_KEY_MANAGER_PROPERTY, 
                                                     &value))) {
            if (value.type == ATX_PROPERTY_VALUE_TYPE_POINTER) {
                self->key_manager = (BLT_KeyManager*)value.data.pointer;
            }
        } else {
            ATX_LOG_FINE("no key manager");
        }

        /* check if we need to use a cipher factory */
        if (ATX_SUCCEEDED(ATX_Properties_GetProperty(properties, 
                                                     BLT_CIPHER_FACTORY_PROPERTY, 
                                                     &value))) {
            if (value.type == ATX_PROPERTY_VALUE_TYPE_POINTER) {
                self->cipher_factory = new BLT_Ap4CipherFactoryAdapter((BLT_CipherFactory*)value.data.pointer);
            }
        } else {
            ATX_LOG_FINE("no cipher factory");
        }
    }

    /* setup interfaces */
    ATX_SET_INTERFACE_EX(self, DcfParser, BLT_BaseMediaNode, BLT_MediaNode);
    ATX_SET_INTERFACE_EX(self, DcfParser, BLT_BaseMediaNode, ATX_Referenceable);
    ATX_SET_INTERFACE(&self->input,  DcfParserInput,  BLT_MediaPort);
    ATX_SET_INTERFACE(&self->input,  DcfParserInput,  BLT_InputStreamUser);
    ATX_SET_INTERFACE(&self->output, DcfParserOutput, BLT_MediaPort);
    ATX_SET_INTERFACE(&self->output, DcfParserOutput, BLT_InputStreamProvider);
}
Пример #14
0
/*----------------------------------------------------------------------
|    BLT_Decoder_Drain
+---------------------------------------------------------------------*/
BLT_Result
BLT_Decoder_Drain(BLT_Decoder* decoder)
{
    BLT_MediaNode* output_node;
    BLT_Result     result;
    
    /* drain the output node */
    result = BLT_Stream_GetOutputNode(decoder->stream, &output_node);
    if (BLT_SUCCEEDED(result) && output_node) {
        BLT_OutputNode* output_node_interface = ATX_CAST(output_node, BLT_OutputNode);
        if (output_node_interface) {
            result = BLT_OutputNode_Drain(output_node_interface);
        } else {
            result = BLT_SUCCESS;
        }
        ATX_RELEASE_OBJECT(output_node);
    } else {
        result = BLT_ERROR_INVALID_STATE;
    }
    
    return result;
}
Пример #15
0
/*----------------------------------------------------------------------
|    BLT_Decoder_SetVolume
+---------------------------------------------------------------------*/
BLT_Result
BLT_Decoder_SetVolume(BLT_Decoder* decoder, float volume)
{
    BLT_MediaNode* output_node;
    BLT_Result     result;
    
    /* get the volume from the output node */
    result = BLT_Stream_GetOutputNode(decoder->stream, &output_node);
    if (BLT_SUCCEEDED(result) && output_node) {
        BLT_VolumeControl* volume_control = ATX_CAST(output_node, BLT_VolumeControl);
        if (volume_control) {
            result = BLT_VolumeControl_SetVolume(volume_control, volume);
        } else {
            result = BLT_ERROR_NOT_SUPPORTED;
        }
        ATX_RELEASE_OBJECT(output_node);
    } else {
        result = BLT_ERROR_INVALID_STATE;
    }
    
    return result;
}
Пример #16
0
/*----------------------------------------------------------------------
|    BLT_Decoder_SetOutput
+---------------------------------------------------------------------*/
BLT_Result
BLT_Decoder_SetOutput(BLT_Decoder* decoder, BLT_CString name, BLT_CString type)
{
    BLT_Result result;

    /* normalize the name and type */
    if (name && name[0] == '\0') name = NULL;
    if (type && type[0] == '\0') type = NULL;

    if (name == NULL) {
        /* if the name is NULL or empty, it means reset */
        BLT_Decoder_OutputChanged(decoder, NULL);
        return BLT_Stream_ResetOutput(decoder->stream);
    } else {
        if (ATX_StringsEqual(name, BLT_DECODER_DEFAULT_OUTPUT_NAME)) {
	        /* if the name is BLT_DECODER_DEFAULT_OUTPUT_NAME, use default */ 
            BLT_CString default_name;
            BLT_CString default_type;
            BLT_Builtins_GetDefaultAudioOutput(&default_name, &default_type);
            name = default_name;
            if (type == NULL) type = default_type;

  	        result = BLT_Stream_SetOutput(decoder->stream, name, type);
	    } else {
            /* set the output of the stream by name */
            result = BLT_Stream_SetOutput(decoder->stream, name, type);
	    }
    }
    
    if (BLT_SUCCEEDED(result)) {
        BLT_MediaNode* node = NULL;
        BLT_Stream_GetOutputNode(decoder->stream, &node);
        BLT_Decoder_OutputChanged(decoder, node);
        ATX_RELEASE_OBJECT(node);
    }

    return result;
}
Пример #17
0
/*----------------------------------------------------------------------
|   Mp4ParserOutput_ProcessCryptoInfo
+---------------------------------------------------------------------*/
static BLT_Result
Mp4ParserOutput_ProcessCryptoInfo(Mp4ParserOutput*        self, 
                                  AP4_SampleDescription*& sample_desc)
{
    // check if the track is encrypted
    if (sample_desc->GetType() == AP4_SampleDescription::TYPE_PROTECTED) {
        ATX_LOG_FINE("track is encrypted");
        AP4_ProtectedSampleDescription* prot_desc = dynamic_cast<AP4_ProtectedSampleDescription*>(sample_desc);
        if (prot_desc == NULL) {
            ATX_LOG_FINE("unable to obtain cipher info");
            return BLT_ERROR_INVALID_MEDIA_FORMAT;
        }

        // obtain the key manager
        if (self->parser->key_manager == NULL) {
            ATX_Properties* properties = NULL;
            if (BLT_SUCCEEDED(BLT_Core_GetProperties(ATX_BASE(self->parser, BLT_BaseMediaNode).core, 
                                                              &properties))) {
                ATX_PropertyValue value;
                if (ATX_SUCCEEDED(ATX_Properties_GetProperty(properties, 
                                                             BLT_KEY_MANAGER_PROPERTY, 
                                                             &value))) {
                    if (value.type == ATX_PROPERTY_VALUE_TYPE_POINTER) {
                        self->parser->key_manager = (BLT_KeyManager*)value.data.pointer;
                    }
                } else {
                    ATX_LOG_FINE("no key manager");
                }
            }
        }
        if (self->parser->key_manager == NULL) return BLT_ERROR_NO_MEDIA_KEY;
        
        // check if we need to use a cipher factory
        if (self->parser->cipher_factory == NULL) {
            ATX_Properties* properties = NULL;
            if (BLT_SUCCEEDED(BLT_Core_GetProperties(ATX_BASE(self->parser, BLT_BaseMediaNode).core, 
                                                              &properties))) {
                ATX_PropertyValue value;
                if (ATX_SUCCEEDED(ATX_Properties_GetProperty(properties, 
                                                             BLT_CIPHER_FACTORY_PROPERTY, 
                                                             &value))) {
                    if (value.type == ATX_PROPERTY_VALUE_TYPE_POINTER) {
                        self->parser->cipher_factory = new BLT_Ap4CipherFactoryAdapter((BLT_CipherFactory*)value.data.pointer);
                    }
                }
            }
        }
        
        // figure out the content ID for this track
        // TODO: support different content ID schemes
        // for now, we just make up a content ID based on the track ID
        char content_id[32];
        NPT_FormatString(content_id, sizeof(content_id), "@track.%d", self->track->GetId());
        
        // get the key for this content
        unsigned int   key_size = 256;
        NPT_DataBuffer key(key_size);
        BLT_Result result = BLT_KeyManager_GetKeyByName(self->parser->key_manager, content_id, key.UseData(), &key_size);
        if (result == ATX_ERROR_NOT_ENOUGH_SPACE) {
            key.SetDataSize(key_size);
            result = BLT_KeyManager_GetKeyByName(self->parser->key_manager, content_id, key.UseData(), &key_size);
        }
        if (BLT_FAILED(result)) return BLT_ERROR_NO_MEDIA_KEY;
        key.SetDataSize(key_size);
        
        delete self->sample_decrypter;
        self->sample_decrypter = AP4_SampleDecrypter::Create(prot_desc, key.GetData(), key_size, self->parser->cipher_factory);
        if (self->sample_decrypter == NULL) {
            ATX_LOG_FINE("unable to create decrypter");
            return BLT_ERROR_CRYPTO_FAILURE;
        }
        
        // switch to the original sample description
        sample_desc = prot_desc->GetOriginalSampleDescription();
    }
    
    return BLT_SUCCESS;
}
/*----------------------------------------------------------------------
|    BLT_DecoderServer::Run
+---------------------------------------------------------------------*/
void
BLT_DecoderServer::Run()
{
    BLT_Result result;

    ATX_LOG_INFO("running");
    
    // create the decoder
    result = BLT_Decoder_Create(&m_Decoder);
    if (BLT_FAILED(result)) {
        m_Client->PostMessage(new BLT_DecoderClient_DecoderEventNotificationMessage(
            BLT_DecoderServer::DecoderEvent::EVENT_TYPE_INIT_ERROR,
            result, 
            "error from BLT_Decoder_Create"));
        WaitForTerminateMessage();
        return;
    }
        
    // register as the event handler
    BLT_Decoder_SetEventListener(m_Decoder, 
                                 &ATX_BASE(&m_EventListener, 
                                           BLT_EventListener));

    // listen to core property changes
    {
        ATX_Properties* properties;
        BLT_Decoder_GetProperties(m_Decoder, &properties);
        ATX_Properties_AddListener(properties, NULL, &ATX_BASE(&m_CorePropertyListener, ATX_PropertyListener), NULL);
    }

    // listen to stream property changes
    {
        ATX_Properties* properties;
        BLT_Decoder_GetStreamProperties(m_Decoder, &properties);
        ATX_Properties_AddListener(properties, NULL, &ATX_BASE(&m_StreamPropertyListener, ATX_PropertyListener), NULL);
    }

    // register builtins 
    result = BLT_Decoder_RegisterBuiltins(m_Decoder);
    if (BLT_FAILED(result)) {
        m_Client->PostMessage(new BLT_DecoderClient_DecoderEventNotificationMessage(
            BLT_DecoderServer::DecoderEvent::EVENT_TYPE_INIT_ERROR,
            result, 
            "error from BLT_Decoder_RegisterBuiltins"));
        WaitForTerminateMessage();
        return;
    }

    // set default output, default type
    result = BLT_Decoder_SetOutput(m_Decoder, 
                                   BLT_DECODER_DEFAULT_OUTPUT_NAME, 
                                   NULL);
    if (BLT_FAILED(result)) {
        m_Client->PostMessage(new BLT_DecoderClient_DecoderEventNotificationMessage(
            BLT_DecoderServer::DecoderEvent::EVENT_TYPE_INIT_ERROR,
            result, 
            "error from BLT_Decoder_SetOutput"));
        //WaitForTerminateMessage();
        //return;
    }
    
    // notify the client of the initial state
    m_Client->PostMessage(
        new BLT_DecoderClient_DecoderStateNotificationMessage(STATE_STOPPED));

    // initial status
    BLT_Decoder_GetStatus(m_Decoder, &m_DecoderStatus);
    m_DecoderStatus.position.range = m_PositionUpdateRange;
    NotifyTimeCode();
    NotifyPosition();

    // initial volume
    float volume=0.0f;
    result = BLT_Decoder_GetVolume(m_Decoder, &volume);
    if (BLT_SUCCEEDED(result)) {
        m_Client->PostMessage(new BLT_DecoderClient_VolumeNotificationMessage(volume));
    }

    SetupIsComplete();

    // decoding loop
    do {
        do {
            result = m_MessageQueue->PumpMessage(0); // non-blocking
        } while (BLT_SUCCEEDED(result));
        
        if (result != NPT_ERROR_LIST_EMPTY) {
            break;
        }

        if (m_State == STATE_PLAYING) {
            result = BLT_Decoder_PumpPacketWithOptions(m_Decoder, BLT_DECODER_PUMP_OPTION_NON_BLOCKING);
            if (BLT_FAILED(result)) {
                if (result == BLT_ERROR_WOULD_BLOCK || result == BLT_ERROR_PORT_HAS_NO_DATA) {
                    /* not fatal, just wait and try again later */
                    ATX_LOG_FINER("pump would block, waiting a short time");
                    result = m_MessageQueue->PumpMessage(BLT_PLAYER_LOOP_WAIT_DURATION);
                } else {
                    ATX_LOG_FINE_1("stopped on %d", result);
                    if (result != BLT_ERROR_EOS) {
                        m_Client->PostMessage(new BLT_DecoderClient_DecoderEventNotificationMessage(
                            BLT_DecoderServer::DecoderEvent::EVENT_TYPE_DECODING_ERROR,
                            result, 
                            "error from BLT_Decoder_PumpPacketWithOptions"));
                    }
                    SetState(STATE_EOS);
                    result = BLT_SUCCESS;
                }
            } else {
                UpdateStatus();
            }
        } else {
            ATX_LOG_FINE("waiting for message");
            result = m_MessageQueue->PumpMessage(NPT_TIMEOUT_INFINITE);
            ATX_LOG_FINE("got message");
        }
    } while (BLT_SUCCEEDED(result) || result == NPT_ERROR_TIMEOUT);

    ATX_LOG_FINE("received Terminate Message");

    // unregister as an event listener
    BLT_Decoder_SetEventListener(m_Decoder, NULL);

    // destroy the decoder
    if (m_Decoder != NULL) {
        BLT_Decoder_Destroy(m_Decoder);
    }  
    
    // we're done
    SetState(STATE_TERMINATED);
}