/*---------------------------------------------------------------------- | DcfParserModule_Attach +---------------------------------------------------------------------*/ BLT_METHOD DcfParserModule_Attach(BLT_Module* _self, BLT_Core* core) { DcfParserModule* self = ATX_SELF_EX(DcfParserModule, BLT_BaseModule, BLT_Module); BLT_Registry* registry; BLT_Result result; /* get the registry */ result = BLT_Core_GetRegistry(core, ®istry); if (BLT_FAILED(result)) return result; /* register the ".dcf" file extension */ result = BLT_Registry_RegisterExtension(registry, ".dcf", "application/vnd.oma.drm.content"); if (BLT_FAILED(result)) return result; /* register the ".odf" file extension */ result = BLT_Registry_RegisterExtension(registry, ".odf", "application/vnd.oma.drm.dcf"); if (BLT_FAILED(result)) return result; /* register the ".oda" file extension */ result = BLT_Registry_RegisterExtension(registry, ".oda", "application/vnd.oma.drm.dcf"); if (BLT_FAILED(result)) return result; /* register the ".odv" file extension */ result = BLT_Registry_RegisterExtension(registry, ".odv", "application/vnd.oma.drm.dcf"); if (BLT_FAILED(result)) return result; /* get the type id for "application/vnd.oma.drm.content" */ result = BLT_Registry_GetIdForName( registry, BLT_REGISTRY_NAME_CATEGORY_MEDIA_TYPE_IDS, "application/vnd.oma.drm.content", &self->dcf1_type_id); if (BLT_FAILED(result)) return result; ATX_LOG_FINE_1("DCF Parser Module::Attach (application/vnd.oma.drm.content type = %d)", self->dcf1_type_id); /* get the type id for "application/vnd.oma.drm.dcf" */ result = BLT_Registry_GetIdForName( registry, BLT_REGISTRY_NAME_CATEGORY_MEDIA_TYPE_IDS, "application/vnd.oma.drm.dcf", &self->dcf2_type_id); if (BLT_FAILED(result)) return result; ATX_LOG_FINE_1("DCF Parser Module::Attach (application/vnd.oma.drm.dcf type = %d)", self->dcf2_type_id); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | BLT_BaseModule_CreateEx +---------------------------------------------------------------------*/ BLT_Result BLT_BaseModule_CreateEx(BLT_CString name, BLT_CString uid, BLT_Flags flags, BLT_Cardinal property_count, const ATX_Property* properties, const BLT_ModuleInterface* module_interface, const ATX_ReferenceableInterface* referenceable_interface, BLT_Size instance_size, BLT_Module** object) { BLT_BaseModule* module; ATX_LOG_FINE_1("creating module name=%s", name); /* allocate memory for the object */ if (instance_size == 0) instance_size = sizeof(BLT_BaseModule); module = (BLT_BaseModule*)ATX_AllocateZeroMemory(instance_size); if (module == NULL) { *object = NULL; return ATX_ERROR_OUT_OF_MEMORY; } /* construct the object */ BLT_BaseModule_ConstructEx(module, name, uid, flags, property_count, properties); /* setup interfaces */ ATX_BASE(module, BLT_Module).iface = module_interface; ATX_BASE(module, ATX_Referenceable).iface = referenceable_interface; *object = &ATX_BASE(module, BLT_Module); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | BLT_DecoderServer::OnSetPropertyCommand +---------------------------------------------------------------------*/ void BLT_DecoderServer::OnSetPropertyCommand(BLT_PropertyScope scope, const NPT_String& /*target*/, const NPT_String& name, const ATX_PropertyValue* value) { BLT_Result result; ATX_LOG_FINE_1("[%s]", name.GetChars()); ATX_Properties* properties = NULL; switch (scope) { case BLT_PROPERTY_SCOPE_CORE: result = BLT_Decoder_GetProperties(m_Decoder, &properties); break; case BLT_PROPERTY_SCOPE_STREAM: result = BLT_Decoder_GetStreamProperties(m_Decoder, &properties); break; default: // not handled yet result = BLT_ERROR_NOT_SUPPORTED; } if (ATX_SUCCEEDED(result) && properties != NULL) { result = ATX_Properties_SetProperty(properties, name.GetChars(), value); } SendReply(BLT_DecoderServer_Message::COMMAND_ID_SET_PROPERTY, result); }
/*---------------------------------------------------------------------- | AlsaOutput_Open +---------------------------------------------------------------------*/ static BLT_Result AlsaOutput_Open(AlsaOutput* self) { int io_result; ATX_LOG_FINE_1("openning output - name=%s", ATX_CSTR(self->device_name)); switch (self->state) { case BLT_ALSA_OUTPUT_STATE_CLOSED: ATX_LOG_FINER("snd_pcm_open"); io_result = snd_pcm_open(&self->device_handle, ATX_CSTR(self->device_name), SND_PCM_STREAM_PLAYBACK, 0); if (io_result != 0) { self->device_handle = NULL; return BLT_FAILURE; } break; case BLT_ALSA_OUTPUT_STATE_OPEN: /* ignore */ return BLT_SUCCESS; case BLT_ALSA_OUTPUT_STATE_CONFIGURED: case BLT_ALSA_OUTPUT_STATE_PREPARED: return BLT_FAILURE; } /* update the state */ AlsaOutput_SetState(self, BLT_ALSA_OUTPUT_STATE_OPEN); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | DcfParserInput_SetStream +---------------------------------------------------------------------*/ BLT_METHOD DcfParserInput_SetStream(BLT_InputStreamUser* _self, ATX_InputStream* stream, const BLT_MediaType* stream_media_type) { DcfParser* self = ATX_SELF_M(input, DcfParser, BLT_InputStreamUser); BLT_Result result; /* check parameters and media type */ if (stream == NULL || stream_media_type == NULL || (stream_media_type->id != self->input.dcf1_media_type.id && stream_media_type->id != self->input.dcf2_media_type.id)) { return BLT_ERROR_INVALID_MEDIA_FORMAT; } /* if we had a stream, release it */ ATX_RELEASE_OBJECT(self->output.stream); /* reset field values */ self->input.encrypted_size = 0; self->input.content_type[0] = 0; self->input.content_uri[0] = 0; self->output.size = 0; /* parse the stream header/info */ if (stream_media_type->id == self->input.dcf1_media_type.id) { result = DcfParser_ParseV1Header(self, stream); } else { result = DcfParser_ParseV2Header(self, stream); } if (BLT_FAILED(result)) return result; /* lookup the media type id */ BLT_Registry* registry = NULL; result = BLT_Core_GetRegistry(ATX_BASE(self, BLT_BaseMediaNode).core, ®istry); if (BLT_FAILED(result)) return result; result = BLT_Registry_GetIdForName( registry, BLT_REGISTRY_NAME_CATEGORY_MEDIA_TYPE_IDS, self->input.content_type, &self->output.media_type.id); if (BLT_FAILED(result)) { ATX_LOG_FINE_1("unregistered content type (%s)", self->input.content_type); return BLT_ERROR_UNSUPPORTED_CODEC; } /* update the stream info */ BLT_StreamInfo stream_info; stream_info.size = self->output.size; stream_info.data_type = self->input.content_type; stream_info.mask = BLT_STREAM_INFO_MASK_SIZE | BLT_STREAM_INFO_MASK_DATA_TYPE; /* update the stream info */ if (stream_info.mask && ATX_BASE(self, BLT_BaseMediaNode).context) { BLT_Stream_SetInfo(ATX_BASE(self, BLT_BaseMediaNode).context, &stream_info); } return result; }
/*---------------------------------------------------------------------- | WaveFormatterModule_Attach +---------------------------------------------------------------------*/ BLT_METHOD WaveFormatterModule_Attach(BLT_Module* _self, BLT_Core* core) { WaveFormatterModule* self = ATX_SELF_EX(WaveFormatterModule, BLT_BaseModule, BLT_Module); BLT_Registry* registry; BLT_Result result; /* get the registry */ result = BLT_Core_GetRegistry(core, ®istry); if (BLT_FAILED(result)) return result; /* register the .wav file extensions */ result = BLT_Registry_RegisterExtension(registry, ".wav", "audio/wav"); if (BLT_FAILED(result)) return result; /* register the "audio/wav" type */ result = BLT_Registry_RegisterName( registry, BLT_REGISTRY_NAME_CATEGORY_MEDIA_TYPE_IDS, "audio/wav", &self->wav_type_id); if (BLT_FAILED(result)) return result; ATX_LOG_FINE_1("WaveFormatterModule::Attach (audio/wav type = %d)", self->wav_type_id); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | BLT_DecoderServer::OnAddNodeCommnand +---------------------------------------------------------------------*/ void BLT_DecoderServer::OnAddNodeCommand(BLT_CString name) { BLT_Result result; ATX_LOG_FINE_1("node name = %s", name); result = BLT_Decoder_AddNodeByName(m_Decoder, NULL, name); SendReply(BLT_DecoderServer_Message::COMMAND_ID_ADD_NODE, result); }
/*---------------------------------------------------------------------- | ATX_HttpClient_SendRequest +---------------------------------------------------------------------*/ ATX_Result ATX_HttpClient_SendRequest(ATX_HttpClient* self, ATX_HttpRequest* request, ATX_HttpResponse** response) { ATX_Cardinal watchdog = ATX_HTTP_MAX_REDIRECTS; ATX_Boolean keep_going; ATX_Result result; do { keep_going = ATX_FALSE; result = ATX_HttpClient_SendRequestOnce(self, request, response); if (ATX_FAILED(result)) break; if (*response && self->options.follow_redirect && (ATX_String_Equals(&request->method, ATX_HTTP_METHOD_GET, ATX_FALSE) || ATX_String_Equals(&request->method, ATX_HTTP_METHOD_HEAD, ATX_FALSE)) && ((*response)->status_code == 301 || (*response)->status_code == 302 || (*response)->status_code == 303 || (*response)->status_code == 307)) { /* handle redirect */ const ATX_String* location = ATX_HttpMessage_GetHeader((ATX_HttpMessage*)*response, ATX_HTTP_HEADER_LOCATION); if (location) { /* replace the request url */ ATX_HttpUrl url; result = ATX_HttpUrl_Construct(&url, ATX_String_GetChars(location)); if (ATX_SUCCEEDED(result)) { ATX_LOG_FINE_1("ATX_HttpClient::SendRequest - redirecting to %s", ATX_String_GetChars(location)); ATX_HttpUrl_Destruct(&request->url); request->url = url; keep_going = ATX_TRUE; ATX_HttpResponse_Destroy(*response); *response = NULL; } else { ATX_LOG_FINE_1("ATX_HttpClient::SendRequest - failed to create redirection URL (%d)", result); break; } } } } while (keep_going && watchdog--); return result; }
/*---------------------------------------------------------------------- | AlsaOutputModule_Probe +---------------------------------------------------------------------*/ BLT_METHOD AlsaOutputModule_Probe(BLT_Module* self, BLT_Core* core, BLT_ModuleParametersType parameters_type, BLT_AnyConst parameters, BLT_Cardinal* match) { BLT_COMPILER_UNUSED(self); BLT_COMPILER_UNUSED(core); switch (parameters_type) { case BLT_MODULE_PARAMETERS_TYPE_MEDIA_NODE_CONSTRUCTOR: { BLT_MediaNodeConstructor* constructor = (BLT_MediaNodeConstructor*)parameters; /* the input protocol should be PACKET and the */ /* output protocol should be NONE */ if ((constructor->spec.input.protocol != BLT_MEDIA_PORT_PROTOCOL_ANY && constructor->spec.input.protocol != BLT_MEDIA_PORT_PROTOCOL_PACKET) || (constructor->spec.output.protocol != BLT_MEDIA_PORT_PROTOCOL_ANY && constructor->spec.output.protocol != BLT_MEDIA_PORT_PROTOCOL_NONE)) { return BLT_FAILURE; } /* the input type should be unknown, or audio/pcm */ if (!(constructor->spec.input.media_type->id == BLT_MEDIA_TYPE_ID_AUDIO_PCM) && !(constructor->spec.input.media_type->id == BLT_MEDIA_TYPE_ID_UNKNOWN)) { return BLT_FAILURE; } /* the name should be 'alsa:<name>' */ if (constructor->name == NULL || !ATX_StringsEqualN(constructor->name, "alsa:", 4)) { return BLT_FAILURE; } /* always an exact match, since we only respond to our name */ *match = BLT_MODULE_PROBE_MATCH_EXACT; ATX_LOG_FINE_1("probe ok [%d]", *match); return BLT_SUCCESS; } break; default: break; } return BLT_FAILURE; }
/*---------------------------------------------------------------------- | BLT_DecoderServer::OnSetVolumeCommand +---------------------------------------------------------------------*/ void BLT_DecoderServer::OnSetVolumeCommand(float volume) { BLT_Result result; ATX_LOG_FINE_1("volume=%f", volume); result = BLT_Decoder_SetVolume(m_Decoder, volume); SendReply(BLT_DecoderServer_Message::COMMAND_ID_SET_VOLUME, result); }
virtual void OnPongNotification(const void* cookie) { ATX_LOG_FINE_1("PONG: %x", (int)cookie); if (!m_JniEnv || !m_Delegate || !m_DelegateMethod) return; jintArray array = (jintArray)m_JniEnv->NewIntArray(1); jint value = (jint)cookie; m_JniEnv->SetIntArrayRegion(array, 0, 1, &value); m_JniEnv->CallVoidMethod(m_Delegate, m_DelegateMethod, com_bluetune_player_Player_MESSAGE_TYPE_PONG, NULL, array); }
virtual void OnVolumeNotification(float volume) { ATX_LOG_FINE_1("VOLUME: %f", volume); if (!m_JniEnv || !m_Delegate || !m_DelegateMethod) return; jintArray array = (jintArray)m_JniEnv->NewIntArray(4); jint values[2] = {(jint)(volume*100.0f), 100}; m_JniEnv->SetIntArrayRegion(array, 0, 2, values); m_JniEnv->CallVoidMethod(m_Delegate, m_DelegateMethod, com_bluetune_player_Player_MESSAGE_TYPE_VOLUME, NULL, array); }
// event listener methods virtual void OnAckNotification(BLT_DecoderServer_Message::CommandId id) { ATX_LOG_FINE_1("ACK: %d", id); if (!m_JniEnv || !m_Delegate || !m_DelegateMethod) return; jintArray array = (jintArray)m_JniEnv->NewIntArray(1); jint value = MapCommandId(id); m_JniEnv->SetIntArrayRegion(array, 0, 1, &value); m_JniEnv->CallVoidMethod(m_Delegate, m_DelegateMethod, com_bluetune_player_Player_MESSAGE_TYPE_ACK, NULL, array); }
virtual void OnDecoderStateNotification(BLT_DecoderServer::State state) { ATX_LOG_FINE_1("DECODER-STATE: %d", (int)state); if (!m_JniEnv || !m_Delegate || !m_DelegateMethod) return; jintArray array = (jintArray)m_JniEnv->NewIntArray(1); jint value = MapDecoderState(state); m_JniEnv->SetIntArrayRegion(array, 0, 1, &value); m_JniEnv->CallVoidMethod(m_Delegate, m_DelegateMethod, com_bluetune_player_Player_MESSAGE_TYPE_DECODER_STATE, NULL, array); }
/*---------------------------------------------------------------------- | BLT_BaseModule_Destroy +---------------------------------------------------------------------*/ BLT_Result BLT_BaseModule_Destroy(BLT_BaseModule* module) { ATX_LOG_FINE_1("destroying module name=%s", module->info.name); BLT_BaseModule_Destruct(module); ATX_FreeMemory((void*)module); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | FileOutputModule_Probe +---------------------------------------------------------------------*/ BLT_METHOD FileOutputModule_Probe(BLT_Module* self, BLT_Core* core, BLT_ModuleParametersType parameters_type, BLT_AnyConst parameters, BLT_Cardinal* match) { BLT_COMPILER_UNUSED(self); BLT_COMPILER_UNUSED(core); switch (parameters_type) { case BLT_MODULE_PARAMETERS_TYPE_MEDIA_NODE_CONSTRUCTOR: { BLT_MediaNodeConstructor* constructor = (BLT_MediaNodeConstructor*)parameters; /* the input protocol should be STREAM_PUSH and the */ /* output protocol should be NONE */ if ((constructor->spec.input.protocol != BLT_MEDIA_PORT_PROTOCOL_ANY && constructor->spec.input.protocol != BLT_MEDIA_PORT_PROTOCOL_STREAM_PUSH) || (constructor->spec.output.protocol != BLT_MEDIA_PORT_PROTOCOL_ANY && constructor->spec.output.protocol != BLT_MEDIA_PORT_PROTOCOL_NONE)) { return BLT_FAILURE; } /* we need a name */ if (constructor->name == NULL) { return BLT_FAILURE; } /* the name needs to be file:<filename> */ if (!ATX_StringsEqualN(constructor->name, "file:", 5)) { return BLT_FAILURE; } /* always an exact match, since we only respond to our name */ *match = BLT_MODULE_PROBE_MATCH_EXACT; ATX_LOG_FINE_1("FileOutputModule::Probe - Ok [%d]", *match); return BLT_SUCCESS; } break; default: break; } return BLT_FAILURE; }
/*---------------------------------------------------------------------- | BLT_BaseModule_Attach +---------------------------------------------------------------------*/ BLT_DIRECT_METHOD BLT_BaseModule_Attach(BLT_Module* _self, BLT_Core* core) { BLT_COMPILER_UNUSED(_self); BLT_COMPILER_UNUSED(core); #if defined(BLT_DEBUG) { BLT_BaseModule* self = ATX_SELF(BLT_BaseModule, BLT_Module); ATX_LOG_FINE_1("attaching module name=%s", self->info.name?self->info.name:""); } #endif return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | 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); }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_CheckDownmix +---------------------------------------------------------------------*/ static void OsxAudioUnitsOutput_CheckDownmix(OsxAudioUnitsOutput* self) { OSStatus err; UInt32 prop_size; err = AudioDeviceGetPropertyInfo(self->audio_device_id, 0, FALSE, kAudioDevicePropertyStreamConfiguration, &prop_size, NULL); if (err != noErr) return; AudioBufferList* buffers = (AudioBufferList *)ATX_AllocateZeroMemory(prop_size); err = AudioDeviceGetProperty(self->audio_device_id, 0, FALSE, kAudioDevicePropertyStreamConfiguration, &prop_size, buffers); if (err == noErr) { unsigned int i; unsigned int channel_count = 0; for (i = 0; i < buffers->mNumberBuffers; ++i) { channel_count += buffers->mBuffers[i].mNumberChannels; } ATX_LOG_FINE_1("device has %d channels", channel_count); } ATX_FreeMemory(buffers); }
/*---------------------------------------------------------------------- | AacDecoderModule_Attach +---------------------------------------------------------------------*/ BLT_METHOD AacDecoderModule_Attach(BLT_Module* _self, BLT_Core* core) { AacDecoderModule* self = ATX_SELF_EX(AacDecoderModule, BLT_BaseModule, BLT_Module); BLT_Registry* registry; BLT_Result result; /* get the registry */ result = BLT_Core_GetRegistry(core, ®istry); if (BLT_FAILED(result)) return result; /* register the type id */ result = BLT_Registry_RegisterName( registry, BLT_REGISTRY_NAME_CATEGORY_MEDIA_TYPE_IDS, BLT_MP4_AUDIO_ES_MIME_TYPE, &self->mp4es_type_id); if (BLT_FAILED(result)) return result; ATX_LOG_FINE_1("AacDecoderModule::Attach (" BLT_MP4_AUDIO_ES_MIME_TYPE " = %d)", self->mp4es_type_id); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | Mp4ParserModule_Probe +---------------------------------------------------------------------*/ BLT_METHOD Mp4ParserModule_Probe(BLT_Module* _self, BLT_Core* core, BLT_ModuleParametersType parameters_type, BLT_AnyConst parameters, BLT_Cardinal* match) { Mp4ParserModule* self = ATX_SELF_EX(Mp4ParserModule, BLT_BaseModule, BLT_Module); BLT_COMPILER_UNUSED(core); switch (parameters_type) { case BLT_MODULE_PARAMETERS_TYPE_MEDIA_NODE_CONSTRUCTOR: { BLT_MediaNodeConstructor* constructor = (BLT_MediaNodeConstructor*)parameters; /* check if we're being probed by name */ if (constructor->name != NULL) { /* we're being probed by name */ if (ATX_StringsEqual(constructor->name, "com.bluetune.parsers.mp4")) { /* our name */ *match = BLT_MODULE_PROBE_MATCH_EXACT; return BLT_SUCCESS; } else { /* not out name */ *match = 0; return BLT_FAILURE; } } /* we need the input protocol to be STREAM_PULL and the output */ /* protocol to be PACKET */ if ((constructor->spec.input.protocol != BLT_MEDIA_PORT_PROTOCOL_ANY && constructor->spec.input.protocol != BLT_MEDIA_PORT_PROTOCOL_STREAM_PULL) || (constructor->spec.output.protocol != BLT_MEDIA_PORT_PROTOCOL_ANY && constructor->spec.output.protocol != BLT_MEDIA_PORT_PROTOCOL_PACKET)) { return BLT_FAILURE; } /* we need the input media type to be 'audio/mp4' or 'video/mp4' */ if (constructor->spec.input.media_type->id != self->mp4_audio_type_id && constructor->spec.input.media_type->id != self->mp4_video_type_id) { return BLT_FAILURE; } /* the output type should be unknown at this point */ if (constructor->spec.output.media_type->id != BLT_MEDIA_TYPE_ID_UNKNOWN) { return BLT_FAILURE; } /* set the match level */ *match = BLT_MODULE_PROBE_MATCH_MAX - 10; ATX_LOG_FINE_1("match %d", *match); return BLT_SUCCESS; } break; default: break; } return BLT_FAILURE; }
/*---------------------------------------------------------------------- | DcfParserModule_Probe +---------------------------------------------------------------------*/ BLT_METHOD DcfParserModule_Probe(BLT_Module* _self, BLT_Core* core, BLT_ModuleParametersType parameters_type, BLT_AnyConst parameters, BLT_Cardinal* match) { DcfParserModule* self = ATX_SELF_EX(DcfParserModule, BLT_BaseModule, BLT_Module); BLT_COMPILER_UNUSED(core); switch (parameters_type) { case BLT_MODULE_PARAMETERS_TYPE_MEDIA_NODE_CONSTRUCTOR: { BLT_MediaNodeConstructor* constructor = (BLT_MediaNodeConstructor*)parameters; /* we need the input protocol to be STREAM_PULL and the output */ /* protocol to be STREAM_PULL */ if ((constructor->spec.input.protocol != BLT_MEDIA_PORT_PROTOCOL_ANY && constructor->spec.input.protocol != BLT_MEDIA_PORT_PROTOCOL_STREAM_PULL) || (constructor->spec.output.protocol != BLT_MEDIA_PORT_PROTOCOL_ANY && constructor->spec.output.protocol != BLT_MEDIA_PORT_PROTOCOL_STREAM_PULL)) { return BLT_FAILURE; } /* we need the input media type to be 'application/vnd.oma.drm.content' */ /* or 'application/vnd.oma.drm.dcf' */ if (constructor->spec.input.media_type->id != self->dcf1_type_id && constructor->spec.input.media_type->id != self->dcf2_type_id) { return BLT_FAILURE; } /* the output type should be unknown at this point */ if (constructor->spec.output.media_type->id != BLT_MEDIA_TYPE_ID_UNKNOWN) { return BLT_FAILURE; } /* compute the match level */ if (constructor->name != NULL) { /* we're being probed by name */ if (ATX_StringsEqual(constructor->name, "DcfParser")) { /* our name */ *match = BLT_MODULE_PROBE_MATCH_EXACT; } else { /* not out name */ return BLT_FAILURE; } } else { /* we're probed by protocol/type specs only */ *match = BLT_MODULE_PROBE_MATCH_MAX - 10; } ATX_LOG_FINE_1("DcfParserModule::Probe - Ok [%d]", *match); return BLT_SUCCESS; } break; default: break; } return BLT_FAILURE; }
/*---------------------------------------------------------------------- | 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); }
/*---------------------------------------------------------------------- | DcfParser_ParseV1Header +---------------------------------------------------------------------*/ static BLT_Result DcfParser_ParseV1Header(DcfParser* self, ATX_InputStream* stream) { /* rewind the byte stream */ ATX_InputStream_Seek(stream, 0); /* user a buffer for parsing */ ATX_UInt8 buffer[3]; /* read the first 3 fields */ ATX_Result result; result = ATX_InputStream_ReadFully(stream, buffer, 3); if (ATX_FAILED(result)) return result; /* check the version */ ATX_UInt8 version = buffer[0]; if (version != 1) { ATX_LOG_FINE_1("unsupported DCF version (%d)", version); return BLT_ERROR_UNSUPPORTED_FORMAT; } /* read the content type */ ATX_UInt8 content_type_length = buffer[1]; self->input.content_type[content_type_length] = 0; // null-terminate result = ATX_InputStream_ReadFully(stream, self->input.content_type, content_type_length); if (ATX_FAILED(result)) return result; /* read the content URI */ ATX_UInt8 content_uri_length = buffer[2]; self->input.content_uri[content_uri_length] = 0; // null-terminate result = ATX_InputStream_ReadFully(stream, self->input.content_uri, content_uri_length); if (ATX_FAILED(result)) return result; /* read the variable-length fields */ unsigned int var_length_1, var_length_2; ATX_UInt32 headers_length = 0; result = DcfParser_ReadUintvar(stream, headers_length, var_length_1); if (ATX_FAILED(result)) return result; ATX_UInt32 data_length = 0; result = DcfParser_ReadUintvar(stream, data_length, var_length_2); if (ATX_FAILED(result)) return result; /* check that the encrypted size makes sense */ if (data_length < 32) return BLT_ERROR_INVALID_MEDIA_FORMAT; self->input.encrypted_size = data_length; /* get the content key */ NPT_DataBuffer key; result = DcfParser_GetContentKey(self, self->input.content_uri, key); if (BLT_FAILED(result)) { ATX_LOG_FINE_2("GetKeyForContent(%s) returned %d", self->input.content_uri, result); return BLT_ERROR_NO_MEDIA_KEY; } /* read the headers */ if (headers_length > BLT_DCF_PARSER_MAX_HEADERS_LENGTH) return BLT_ERROR_INVALID_MEDIA_FORMAT; char* headers = new char[headers_length+1]; headers[headers_length] = '\0'; result = ATX_InputStream_ReadFully(stream, headers, headers_length); if (ATX_FAILED(result)) { delete[] headers; return result; } /* as a first-order estimate, set the output size to the encrypted size minus the IV */ self->output.size = self->input.encrypted_size-16; /* parse the headers */ NPT_MemoryStream* headers_memory_stream = new NPT_MemoryStream(headers, headers_length); NPT_InputStreamReference headers_memory_stream_ref(headers_memory_stream); NPT_BufferedInputStream* headers_buffered_stream = new NPT_BufferedInputStream(headers_memory_stream_ref); NPT_HttpHeaders content_headers; content_headers.Parse(*headers_buffered_stream); delete headers_buffered_stream; delete[] headers; /* find out about the encryption from the headers */ const NPT_String* encryption_method = content_headers.GetHeaderValue("Encryption-Method"); if (encryption_method == NULL) return BLT_ERROR_INVALID_MEDIA_FORMAT; /* check the encryption method */ bool encryption_supported = false; NPT_Map<NPT_String,NPT_String> encryption_params; NPT_Size algorithm_id_length = 0; /* parse the algorithm id */ int separator = encryption_method->Find(';', 0, true); if (separator > 0) { algorithm_id_length = separator; /* parse the params */ result = NPT_ParseMimeParameters(((const char*)(*encryption_method))+separator+1, encryption_params); if (NPT_FAILED(result)) { ATX_LOG_FINE_1("cannot parse Encryption-Method parameters (%s)", (const char*)encryption_method); return BLT_ERROR_INVALID_MEDIA_FORMAT; } /* parse the plaintext-length header, if present */ NPT_String* plaintext_length = NULL; if (NPT_SUCCEEDED(encryption_params.Get("plaintext-length", plaintext_length))) { NPT_UInt64 value = 0; if (NPT_SUCCEEDED(plaintext_length->ToInteger64(value, true))) { self->output.size = value; } } } else { algorithm_id_length = encryption_method->GetLength(); } if (NPT_StringsEqualN((const char*)(*encryption_method), BLT_DCF_PARSER_ALGORITHM_ID_AES128CBC, algorithm_id_length)) { encryption_supported = true; NPT_String* padding = NULL; if (NPT_SUCCEEDED(encryption_params.Get("padding", padding))) { if (*padding == BLT_DCF_PARSER_PADDING_RFC2630) { encryption_supported = false; // hmmm, unknown padding } } } if (!encryption_supported) { ATX_LOG_FINE_1("unsupported encryption format (%s)", encryption_method); return BLT_ERROR_UNSUPPORTED_FORMAT; } /* read the IV */ AP4_UI08 iv[16]; result = ATX_InputStream_ReadFully(stream, iv, sizeof(iv)); if (BLT_FAILED(result)) return result; /* create a byte stream to represent the encrypted data */ ATX_Size header_size = 3+content_type_length+content_uri_length+var_length_1+var_length_2+headers_length; ATX_InputStream* data_stream = NULL; ATX_SubInputStream_Create(stream, header_size+16, // skip the IV self->input.encrypted_size-16, NULL, &data_stream); ATX_InputStream_To_AP4_ByteStream_Adapter* encrypted_stream = new ATX_InputStream_To_AP4_ByteStream_Adapter(data_stream); ATX_RELEASE_OBJECT(data_stream); /* create a decrypting stream for the content */ // FIXME: temporary AP4_ByteStream* decrypting_stream = NULL; result = AP4_DecryptingStream::Create(AP4_BlockCipher::CBC, *encrypted_stream, self->output.size, iv, 16, key.GetData(), key.GetDataSize(), self->cipher_factory, decrypting_stream); encrypted_stream->Release(); if (AP4_FAILED(result)) return result; /* create a reverse adapter */ result = AP4_ByteStream_To_ATX_InputStream_Adapter_Create(decrypting_stream, &self->output.stream); decrypting_stream->Release(); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | SdlVideoOutput_PutPacket +---------------------------------------------------------------------*/ BLT_METHOD SdlVideoOutput_PutPacket(BLT_PacketConsumer* _self, BLT_MediaPacket* packet) { SdlVideoOutput* self = ATX_SELF(SdlVideoOutput, BLT_PacketConsumer); unsigned char* pixel_data = (unsigned char*)BLT_MediaPacket_GetPayloadBuffer(packet); const BLT_RawVideoMediaType* media_type; unsigned int plane; SDL_Rect rect; /* check the media type */ BLT_MediaPacket_GetMediaType(packet, (const BLT_MediaType**)&media_type); if (media_type->base.id != BLT_MEDIA_TYPE_ID_VIDEO_RAW) { ATX_LOG_FINE_1("rejecting media type id %d", media_type->base.id); return BLT_ERROR_INVALID_MEDIA_TYPE; } if (media_type->format != BLT_PIXEL_FORMAT_YV12) { ATX_LOG_FINE_1("rejecting pixel format %d", media_type->format); return BLT_ERROR_INVALID_MEDIA_TYPE; } /* resize/create the window and overlay if needed */ if (self->yuv_overlay == NULL || self->yuv_overlay->w != media_type->width || self->yuv_overlay->h != media_type->height) { self->screen = SDL_SetVideoMode(media_type->width, media_type->height, 24, SDL_HWSURFACE | SDL_RESIZABLE); if (self->screen == NULL) { ATX_LOG_WARNING("SDL_SetVideoMode() failed"); return BLT_FAILURE; } self->yuv_overlay = SDL_CreateYUVOverlay(media_type->width, media_type->height, SDL_YV12_OVERLAY, self->screen); if (self->yuv_overlay == NULL) { ATX_LOG_WARNING("SDL_CreateYUVOverlay() failed"); return BLT_FAILURE; } } /* transfer the pixels */ SDL_LockYUVOverlay(self->yuv_overlay); for (plane=0; plane<3; plane++) { unsigned int plane_width = (plane==0?media_type->width:(media_type->width/2)); unsigned int plane_height = (plane==0?media_type->height:(media_type->height/2)); unsigned char* src = pixel_data+media_type->planes[plane].offset; unsigned int src_pitch = media_type->planes[plane].bytes_per_line; unsigned char* dst = self->yuv_overlay->pixels[plane==0?0:3-plane]; unsigned int dst_pitch = self->yuv_overlay->pitches[plane==0?0:3-plane]; while (plane_height--) { ATX_CopyMemory(dst, src, plane_width); src += src_pitch; dst += dst_pitch; } } SDL_UnlockYUVOverlay(self->yuv_overlay); rect.x = 0; rect.y = 0; rect.w = self->screen->w; rect.h = self->screen->h; SDL_DisplayYUVOverlay(self->yuv_overlay, &rect); { ATX_TimeStamp now; ATX_System_GetCurrentTimeStamp(&now); if (ATX_TimeStamp_IsLaterOrEqual(self->next_display_time, now)) { ATX_TimeInterval delta; ATX_TimeStamp_Sub(delta, self->next_display_time, now); /* sanity check */ if (delta.seconds == 0 && delta.nanoseconds > 1000000) { ATX_System_Sleep(&delta); } } else { self->next_display_time = now; } { ATX_TimeStamp frame_duration = {0, 41708000}; ATX_TimeStamp_Add(self->next_display_time, self->next_display_time, frame_duration); } } return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | CrossFaderModule_Probe +---------------------------------------------------------------------*/ BLT_METHOD CrossFaderModule_Probe(BLT_ModuleInstance* instance, BLT_Core* core, BLT_ModuleParametersType parameters_type, BLT_AnyConst parameters, BLT_Cardinal* match) { BLT_COMPILER_UNUSED(core); BLT_COMPILER_UNUSED(instance); switch (parameters_type) { case BLT_MODULE_PARAMETERS_TYPE_MEDIA_NODE_CONSTRUCTOR: { BLT_MediaNodeConstructor* constructor = (BLT_MediaNodeConstructor*)parameters; /* we need a name */ if (constructor->name == NULL || !ATX_StringsEqual(constructor->name, "CrossFader")) { return BLT_FAILURE; } /* the input and output protocols should be PACKET */ if ((constructor->spec.input.protocol != BLT_MEDIA_PORT_PROTOCOL_ANY && constructor->spec.input.protocol != BLT_MEDIA_PORT_PROTOCOL_PACKET) || (constructor->spec.output.protocol != BLT_MEDIA_PORT_PROTOCOL_ANY && constructor->spec.output.protocol != BLT_MEDIA_PORT_PROTOCOL_PACKET)) { return BLT_FAILURE; } /* the input type should be unspecified, or audio/pcm */ if (!(constructor->spec.input.media_type->id == BLT_MEDIA_TYPE_ID_AUDIO_PCM) && !(constructor->spec.input.media_type->id == BLT_MEDIA_TYPE_ID_UNKNOWN)) { return BLT_FAILURE; } /* the output type should be unspecified, or audio/pcm */ if (!(constructor->spec.output.media_type->id == BLT_MEDIA_TYPE_ID_AUDIO_PCM) && !(constructor->spec.output.media_type->id == BLT_MEDIA_TYPE_ID_UNKNOWN)) { return BLT_FAILURE; } /* match level is always exact */ *match = BLT_MODULE_PROBE_MATCH_EXACT; ATX_LOG_FINE_1("CrossFaderModule::Probe - Ok [%d]", *match); return BLT_SUCCESS; } break; default: break; } return BLT_FAILURE; }
/*---------------------------------------------------------------------- | PcmAdapterModule_Probe +---------------------------------------------------------------------*/ BLT_METHOD PcmAdapterModule_Probe(BLT_Module* self, BLT_Core* core, BLT_ModuleParametersType parameters_type, BLT_AnyConst parameters, BLT_Cardinal* match) { BLT_COMPILER_UNUSED(self); BLT_COMPILER_UNUSED(core); switch (parameters_type) { case BLT_MODULE_PARAMETERS_TYPE_MEDIA_NODE_CONSTRUCTOR: { BLT_MediaNodeConstructor* constructor = (BLT_MediaNodeConstructor*)parameters; /* compute match based on specified name */ if (constructor->name == NULL) { *match = BLT_MODULE_PROBE_MATCH_DEFAULT; /* the input protocol should be PACKET */ if (constructor->spec.input.protocol != BLT_MEDIA_PORT_PROTOCOL_PACKET) { return BLT_FAILURE; } /* output protocol should be PACKET */ if (constructor->spec.output.protocol != BLT_MEDIA_PORT_PROTOCOL_PACKET) { return BLT_FAILURE; } /* check that the in and out formats are supported */ if (!BLT_Pcm_CanConvert(constructor->spec.input.media_type, constructor->spec.output.media_type)) { return BLT_FAILURE; } } else { /* if a name is specified, it needs to match exactly */ if (!ATX_StringsEqual(constructor->name, "PcmAdapter")) { return BLT_FAILURE; } else { *match = BLT_MODULE_PROBE_MATCH_EXACT; } /* the input protocol should be PACKET or ANY */ if (constructor->spec.input.protocol != BLT_MEDIA_PORT_PROTOCOL_ANY && constructor->spec.input.protocol != BLT_MEDIA_PORT_PROTOCOL_PACKET) { return BLT_FAILURE; } /* output protocol should be PACKET or ANY */ if ((constructor->spec.output.protocol != BLT_MEDIA_PORT_PROTOCOL_ANY && constructor->spec.output.protocol != BLT_MEDIA_PORT_PROTOCOL_PACKET)) { return BLT_FAILURE; } /* check that the in and out formats are supported */ if (!BLT_Pcm_CanConvert(constructor->spec.input.media_type, constructor->spec.output.media_type)) { return BLT_FAILURE; } } ATX_LOG_FINE_1("PcmAdapterModule::Probe - Ok [%d]", *match); return BLT_SUCCESS; } break; default: break; } return BLT_FAILURE; }
/*---------------------------------------------------------------------- | Mp4Parser_Seek +---------------------------------------------------------------------*/ BLT_METHOD Mp4Parser_Seek(BLT_MediaNode* _self, BLT_SeekMode* mode, BLT_SeekPoint* point) { Mp4Parser* self = ATX_SELF_EX(Mp4Parser, BLT_BaseMediaNode, BLT_MediaNode); /* estimate the seek point */ if (ATX_BASE(self, BLT_BaseMediaNode).context == NULL) return BLT_FAILURE; BLT_Stream_EstimateSeekPoint(ATX_BASE(self, BLT_BaseMediaNode).context, *mode, point); if (!(point->mask & BLT_SEEK_POINT_MASK_TIME_STAMP)) { return BLT_FAILURE; } /* seek to the estimated offset on all tracks */ AP4_Ordinal sample_index = 0; AP4_UI32 ts_ms = point->time_stamp.seconds*1000+point->time_stamp.nanoseconds/1000000; if (self->video_output.track) { AP4_Result result = self->video_output.track->GetSampleIndexForTimeStampMs(ts_ms, sample_index); if (AP4_FAILED(result)) { ATX_LOG_WARNING_1("video GetSampleIndexForTimeStampMs failed (%d)", result); return BLT_FAILURE; } ATX_LOG_FINE_1("seeking to video time %d ms", ts_ms); // go to the nearest sync sample self->video_output.sample = self->video_output.track->GetNearestSyncSampleIndex(sample_index); if (self->input.reader) { self->input.reader->SetSampleIndex(self->video_output.track->GetId(), self->video_output.sample); } ATX_LOG_FINE_1("seeking to video sync sample %d", self->video_output.sample); // compute the timestamp of the video sample we're seeking to, so we can pick an audio // sample that is close in time (there are many more audio sync points than video) AP4_Sample sample; if (AP4_SUCCEEDED(self->video_output.track->GetSample(self->video_output.sample, sample))) { AP4_UI32 media_timescale = self->video_output.track->GetMediaTimeScale(); if (media_timescale) { ts_ms = (AP4_UI32)((((AP4_UI64)sample.GetCts())*1000)/media_timescale); ATX_LOG_FINE_1("sync sample time is %d ms", ts_ms); } } else { ATX_LOG_FINE_1("unable to get sample info for sample %d", self->video_output.sample); } } if (self->audio_output.track) { AP4_Result result = self->audio_output.track->GetSampleIndexForTimeStampMs(ts_ms, sample_index); if (AP4_FAILED(result)) { ATX_LOG_WARNING_1("audio GetSampleIndexForTimeStampMs failed (%d)", result); return BLT_FAILURE; } self->audio_output.sample = sample_index; if (self->input.reader) { self->input.reader->SetSampleIndex(self->audio_output.track->GetId(), sample_index); } } /* set the mode so that the nodes down the chain know the seek has */ /* already been done on the stream */ *mode = BLT_SEEK_MODE_IGNORE; return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | Mp4ParserModule_Attach +---------------------------------------------------------------------*/ BLT_METHOD Mp4ParserModule_Attach(BLT_Module* _self, BLT_Core* core) { Mp4ParserModule* self = ATX_SELF_EX(Mp4ParserModule, BLT_BaseModule, BLT_Module); BLT_Registry* registry; BLT_Result result; /* get the registry */ result = BLT_Core_GetRegistry(core, ®istry); if (BLT_FAILED(result)) return result; /* register the ".mp4" file extension */ result = BLT_Registry_RegisterExtension(registry, ".mp4", "video/mp4"); if (BLT_FAILED(result)) return result; /* register the ".m4a" file extension */ result = BLT_Registry_RegisterExtension(registry, ".m4a", "audio/mp4"); if (BLT_FAILED(result)) return result; /* register the ".m4v" file extension */ result = BLT_Registry_RegisterExtension(registry, ".m4v", "video/mp4"); if (BLT_FAILED(result)) return result; /* register the ".m4p" file extension */ result = BLT_Registry_RegisterExtension(registry, ".m4p", "video/mp4"); if (BLT_FAILED(result)) return result; /* register the ".3gp" file extension */ result = BLT_Registry_RegisterExtension(registry, ".3gp", "video/mp4"); if (BLT_FAILED(result)) return result; /* register the ".3gp" file extension */ result = BLT_Registry_RegisterExtension(registry, ".mov", "video/mp4"); if (BLT_FAILED(result)) return result; /* get the type id for "audio/mp4" */ result = BLT_Registry_GetIdForName( registry, BLT_REGISTRY_NAME_CATEGORY_MEDIA_TYPE_IDS, "audio/mp4", &self->mp4_audio_type_id); if (BLT_FAILED(result)) return result; ATX_LOG_FINE_1("audio/mp4 type = %d", self->mp4_audio_type_id); /* get the type id for "video/mp4" */ result = BLT_Registry_GetIdForName( registry, BLT_REGISTRY_NAME_CATEGORY_MEDIA_TYPE_IDS, "video/mp4", &self->mp4_video_type_id); if (BLT_FAILED(result)) return result; ATX_LOG_FINE_1("video/mp4 type = %d", self->mp4_video_type_id); /* register the type id for BLT_MP4_AUDIO_ES_MIME_TYPE */ result = BLT_Registry_RegisterName( registry, BLT_REGISTRY_NAME_CATEGORY_MEDIA_TYPE_IDS, BLT_MP4_AUDIO_ES_MIME_TYPE, &self->mp4_audio_es_type_id); if (BLT_FAILED(result)) return result; ATX_LOG_FINE_1(BLT_MP4_AUDIO_ES_MIME_TYPE " type = %d", self->mp4_audio_es_type_id); /* register the type id for BLT_MP4_VIDEO_ES_MIME_TYPE */ result = BLT_Registry_RegisterName( registry, BLT_REGISTRY_NAME_CATEGORY_MEDIA_TYPE_IDS, BLT_MP4_VIDEO_ES_MIME_TYPE, &self->mp4_video_es_type_id); if (BLT_FAILED(result)) return result; ATX_LOG_FINE_1(BLT_MP4_VIDEO_ES_MIME_TYPE " type = %d", self->mp4_video_es_type_id); /* register the type id for BLT_ISO_BASE_AUDIO_ES_MIME_TYPE */ result = BLT_Registry_RegisterName( registry, BLT_REGISTRY_NAME_CATEGORY_MEDIA_TYPE_IDS, BLT_ISO_BASE_AUDIO_ES_MIME_TYPE, &self->iso_base_audio_es_type_id); if (BLT_FAILED(result)) return result; ATX_LOG_FINE_1(BLT_ISO_BASE_AUDIO_ES_MIME_TYPE " type = %d", self->iso_base_audio_es_type_id); /* register the type id for BLT_ISO_BASE_VIDEO_ES_MIME_TYPE */ result = BLT_Registry_RegisterName( registry, BLT_REGISTRY_NAME_CATEGORY_MEDIA_TYPE_IDS, BLT_ISO_BASE_VIDEO_ES_MIME_TYPE, &self->iso_base_video_es_type_id); if (BLT_FAILED(result)) return result; ATX_LOG_FINE_1(BLT_ISO_BASE_VIDEO_ES_MIME_TYPE " type = %d", self->iso_base_video_es_type_id); /* register mime type aliases */ BLT_Registry_RegisterNameForId(registry, BLT_REGISTRY_NAME_CATEGORY_MEDIA_TYPE_IDS, "audio/m4a", self->mp4_audio_type_id); BLT_Registry_RegisterNameForId(registry, BLT_REGISTRY_NAME_CATEGORY_MEDIA_TYPE_IDS, "video/m4v", self->mp4_video_type_id); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | AacDecoderModule_Probe +---------------------------------------------------------------------*/ BLT_METHOD AacDecoderModule_Probe(BLT_Module* _self, BLT_Core* core, BLT_ModuleParametersType parameters_type, BLT_AnyConst parameters, BLT_Cardinal* match) { AacDecoderModule* self = ATX_SELF_EX(AacDecoderModule, BLT_BaseModule, BLT_Module); BLT_COMPILER_UNUSED(core); switch (parameters_type) { case BLT_MODULE_PARAMETERS_TYPE_MEDIA_NODE_CONSTRUCTOR: { BLT_MediaNodeConstructor* constructor = (BLT_MediaNodeConstructor*)parameters; /* the input and output protocols should be PACKET */ if ((constructor->spec.input.protocol != BLT_MEDIA_PORT_PROTOCOL_ANY && constructor->spec.input.protocol != BLT_MEDIA_PORT_PROTOCOL_PACKET) || (constructor->spec.output.protocol != BLT_MEDIA_PORT_PROTOCOL_ANY && constructor->spec.output.protocol != BLT_MEDIA_PORT_PROTOCOL_PACKET)) { return BLT_FAILURE; } /* the input type should be BLT_MP4_ES_MIME_TYPE */ if (constructor->spec.input.media_type->id != self->mp4es_type_id) { return BLT_FAILURE; } else { /* check the object type id */ BLT_Mp4AudioMediaType* media_type = (BLT_Mp4AudioMediaType*)constructor->spec.input.media_type; if (media_type->base.stream_type != BLT_MP4_STREAM_TYPE_AUDIO) return BLT_FAILURE; if (media_type->base.format_or_object_type_id != BLT_AAC_OBJECT_TYPE_ID_MPEG2_AAC_LC && media_type->base.format_or_object_type_id != BLT_AAC_OBJECT_TYPE_ID_MPEG4_AUDIO) { return BLT_FAILURE; } if (media_type->base.format_or_object_type_id == BLT_AAC_OBJECT_TYPE_ID_MPEG4_AUDIO) { /* check that this is AAC LC */ AacDecoderConfig decoder_config; if (BLT_FAILED(AacDecoderConfig_Parse(media_type->decoder_info, media_type->decoder_info_length, &decoder_config))) { return BLT_FAILURE; } if (decoder_config.object_type != BLT_AAC_OBJECT_TYPE_AAC_LC && decoder_config.object_type != BLT_AAC_OBJECT_TYPE_SBR) { return BLT_FAILURE; } } } /* the output type should be unspecified, or audio/pcm */ if (!(constructor->spec.output.media_type->id == BLT_MEDIA_TYPE_ID_AUDIO_PCM) && !(constructor->spec.output.media_type->id == BLT_MEDIA_TYPE_ID_UNKNOWN)) { return BLT_FAILURE; } /* compute the match level */ if (constructor->name != NULL) { /* we're being probed by name */ if (ATX_StringsEqual(constructor->name, "AacDecoder")) { /* our name */ *match = BLT_MODULE_PROBE_MATCH_EXACT; } else { /* not our name */ return BLT_FAILURE; } } else { /* we're probed by protocol/type specs only */ *match = BLT_MODULE_PROBE_MATCH_MAX - 10; } ATX_LOG_FINE_1("AacDecoderModule::Probe - Ok [%d]", *match); return BLT_SUCCESS; } break; default: break; } return BLT_FAILURE; }