/*---------------------------------------------------------------------- | AlsaOutput_Seek +---------------------------------------------------------------------*/ BLT_METHOD AlsaOutput_Seek(BLT_MediaNode* _self, BLT_SeekMode* mode, BLT_SeekPoint* point) { AlsaOutput* self = ATX_SELF_EX(AlsaOutput, BLT_BaseMediaNode, BLT_MediaNode); BLT_COMPILER_UNUSED(mode); BLT_COMPILER_UNUSED(point); /* ignore unless we're prepared */ if (self->state != BLT_ALSA_OUTPUT_STATE_PREPARED) { return BLT_SUCCESS; } /* reset the device */ AlsaOutput_Reset(self); /* update the media time */ if (point->mask & BLT_SEEK_POINT_MASK_TIME_STAMP) { self->media_time = BLT_TimeStamp_ToNanos(point->time_stamp); self->next_media_time = self->media_time; } else { self->media_time = 0; self->next_media_time = 0; } return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_Seek +---------------------------------------------------------------------*/ BLT_METHOD OsxAudioUnitsOutput_Seek(BLT_MediaNode* _self, BLT_SeekMode* mode, BLT_SeekPoint* point) { OsxAudioUnitsOutput* self = ATX_SELF_EX(OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode); ComponentResult result; BLT_COMPILER_UNUSED(mode); BLT_COMPILER_UNUSED(point); /* flush the queue */ pthread_mutex_lock(&self->lock); ATX_List_Clear(self->packet_queue); pthread_mutex_unlock(&self->lock); /* reset the device */ result = AudioUnitReset(self->audio_unit, kAudioUnitScope_Input, 0); if (result != noErr) { ATX_LOG_WARNING_1("AudioUnitReset failed (%d)", (int)result); } return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | WaveFormatter_Deactivate +---------------------------------------------------------------------*/ BLT_METHOD WaveFormatter_Deactivate(BLT_MediaNode* _self) { WaveFormatter* self = ATX_SELF_EX(WaveFormatter, BLT_BaseMediaNode, BLT_MediaNode); ATX_LOG_FINER("WaveFormatter::Deactivate"); /* update the header if needed */ if (self->output.stream) { ATX_Position where = 0; ATX_OutputStream_Tell(self->output.stream, &where); self->input.size = where; if (self->input.size >= BLT_WAVE_FORMATTER_RIFF_HEADER_SIZE) { self->input.size -= BLT_WAVE_FORMATTER_RIFF_HEADER_SIZE; } /* update the header */ WaveFormatter_UpdateWavHeader(self); /* set the stream back to its original position */ ATX_OutputStream_Seek(self->output.stream, where); } /* release the output stream */ ATX_RELEASE_OBJECT(self->output.stream); /* call the base class method */ BLT_BaseMediaNode_Deactivate(_self); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | WaveParser_Seek +---------------------------------------------------------------------*/ BLT_METHOD WaveParser_Seek(BLT_MediaNode* _self, BLT_SeekMode* mode, BLT_SeekPoint* point) { WaveParser* self = ATX_SELF_EX(WaveParser, 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_OFFSET)) { return BLT_FAILURE; } /* align the offset to the nearest sample */ point->offset -= point->offset%(self->output.block_size); /* seek to the estimated offset */ /* seek into the input stream (ignore return value) */ ATX_InputStream_Seek(self->output.stream, point->offset); /* 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; }
/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | AlsaOutput_Deactivate +---------------------------------------------------------------------*/ BLT_METHOD AlsaOutput_Deactivate(BLT_MediaNode* _self) { AlsaOutput* self = ATX_SELF_EX(AlsaOutput, BLT_BaseMediaNode, BLT_MediaNode); ATX_LOG_FINER("deactivating output"); /* close the device */ AlsaOutput_Close(self); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | AlsaOutput_Stop +---------------------------------------------------------------------*/ BLT_METHOD AlsaOutput_Stop(BLT_MediaNode* _self) { AlsaOutput* self = ATX_SELF_EX(AlsaOutput, BLT_BaseMediaNode, BLT_MediaNode); ATX_LOG_FINER("stopping output"); /* reset the device */ AlsaOutput_Reset(self); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | AlsaOutput_Activate +---------------------------------------------------------------------*/ BLT_METHOD AlsaOutput_Activate(BLT_MediaNode* _self, BLT_Stream* stream) { AlsaOutput* self = ATX_SELF_EX(AlsaOutput, BLT_BaseMediaNode, BLT_MediaNode); BLT_COMPILER_UNUSED(stream); ATX_LOG_FINER("activating output"); /* open the device */ AlsaOutput_Open(self); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_Start +---------------------------------------------------------------------*/ BLT_METHOD OsxAudioUnitsOutput_Start(BLT_MediaNode* _self) { OsxAudioUnitsOutput* self = ATX_SELF_EX(OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode); ComponentResult result; /* start the audio unit */ result = AudioOutputUnitStart(self->audio_unit); if (result != noErr) { ATX_LOG_WARNING_1("AudioUnitOutputStart failed (%d)", (int)result); } return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | AlsaOutput_GetPortByName +---------------------------------------------------------------------*/ BLT_METHOD AlsaOutput_GetPortByName(BLT_MediaNode* _self, BLT_CString name, BLT_MediaPort** port) { AlsaOutput* self = ATX_SELF_EX(AlsaOutput, BLT_BaseMediaNode, BLT_MediaNode); if (ATX_StringsEqual(name, "input")) { *port = &ATX_BASE(self, BLT_MediaPort); return BLT_SUCCESS; } else { *port = NULL; return BLT_ERROR_NO_SUCH_PORT; } }
/*---------------------------------------------------------------------- | DcfParser_Deactivate +---------------------------------------------------------------------*/ BLT_METHOD DcfParser_Deactivate(BLT_MediaNode* _self) { DcfParser* self = ATX_SELF_EX(DcfParser, BLT_BaseMediaNode, BLT_MediaNode); ATX_LOG_FINER("DcfParser::Deactivate"); /* release the stream */ ATX_RELEASE_OBJECT(self->output.stream); /* call the base class method */ BLT_BaseMediaNode_Deactivate(_self); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_Resume +---------------------------------------------------------------------*/ BLT_METHOD OsxAudioUnitsOutput_Resume(BLT_MediaNode* _self) { OsxAudioUnitsOutput* self = ATX_SELF_EX(OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode); ComponentResult result; if (self->paused) { ATX_LOG_FINE("resuming output"); self->paused = BLT_FALSE; result = AudioOutputUnitStart(self->audio_unit); if (result != noErr) { ATX_LOG_WARNING_1("AudioUnitOutputStart failed (%d)", (int)result); } } return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | DcfParser_GetPortByName +---------------------------------------------------------------------*/ BLT_METHOD DcfParser_GetPortByName(BLT_MediaNode* _self, BLT_CString name, BLT_MediaPort** port) { DcfParser* self = ATX_SELF_EX(DcfParser, BLT_BaseMediaNode, BLT_MediaNode); if (ATX_StringsEqual(name, "input")) { *port = &ATX_BASE(&self->input, BLT_MediaPort); return BLT_SUCCESS; } else if (ATX_StringsEqual(name, "output")) { *port = &ATX_BASE(&self->output, BLT_MediaPort); return BLT_SUCCESS; } else { *port = NULL; return BLT_ERROR_NO_SUCH_PORT; } }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_Deactivate +---------------------------------------------------------------------*/ BLT_METHOD OsxAudioUnitsOutput_Deactivate(BLT_MediaNode* _self) { OsxAudioUnitsOutput* self = ATX_SELF_EX(OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode); ComponentResult result; ATX_LOG_FINER("OsxAudioUnitsOutput::Deactivate"); /* un-initialize the device */ if (self->audio_unit) { result = AudioUnitUninitialize(self->audio_unit); if (result != noErr) { ATX_LOG_WARNING_1("AudioUnitUninitialize failed (%d)", (int)result); return BLT_FAILURE; } } return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | AlsaOutput_Resume +---------------------------------------------------------------------*/ BLT_METHOD AlsaOutput_Resume(BLT_MediaNode* _self) { AlsaOutput* self = ATX_SELF_EX(AlsaOutput, BLT_BaseMediaNode, BLT_MediaNode); ATX_LOG_FINER("resuming output"); /* pause the device */ switch (self->state) { case BLT_ALSA_OUTPUT_STATE_PREPARED: snd_pcm_pause(self->device_handle, 0); break; default: /* ignore */ break; } return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | AacDecoder_Seek +---------------------------------------------------------------------*/ BLT_METHOD AacDecoder_Seek(BLT_MediaNode* _self, BLT_SeekMode* mode, BLT_SeekPoint* point) { AacDecoder* self = ATX_SELF_EX(AacDecoder, BLT_BaseMediaNode, BLT_MediaNode); BLT_COMPILER_UNUSED(mode); BLT_COMPILER_UNUSED(point); /* clear the eos flag */ self->input.eos = BLT_FALSE; /* remove any packets in the output list */ AacDecoderOutput_Flush(self); /* reset the decoder */ if (self->helix_decoder) AACFlushCodec(self->helix_decoder); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_Stop +---------------------------------------------------------------------*/ BLT_METHOD OsxAudioUnitsOutput_Stop(BLT_MediaNode* _self) { OsxAudioUnitsOutput* self = ATX_SELF_EX(OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode); ComponentResult result; /* flush the queue */ pthread_mutex_lock(&self->lock); ATX_List_Clear(self->packet_queue); pthread_mutex_unlock(&self->lock); /* stop the and reset audio unit */ result = AudioOutputUnitStop(self->audio_unit); if (result != noErr) { ATX_LOG_WARNING_1("AudioUnitOutputStop failed (%d)", (int)result); } result = AudioUnitReset(self->audio_unit, kAudioUnitScope_Input, 0); if (result != noErr) { ATX_LOG_WARNING_1("AudioUnitReset failed (%d)", (int)result); } 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; }
/*---------------------------------------------------------------------- | WaveFormatterModule_Probe +---------------------------------------------------------------------*/ BLT_METHOD WaveFormatterModule_Probe(BLT_Module* _self, BLT_Core* core, BLT_ModuleParametersType parameters_type, BLT_AnyConst parameters, BLT_Cardinal* match) { WaveFormatterModule* self = ATX_SELF_EX(WaveFormatterModule, 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 protocol should be STREAM_PUSH and the */ /* output protocol should be STREAM_PUSH */ 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_STREAM_PUSH)) { return BLT_FAILURE; } /* the input type should be audio/pcm */ if (constructor->spec.input.media_type->id != BLT_MEDIA_TYPE_ID_AUDIO_PCM) { return BLT_FAILURE; } /* compute the match level */ if (constructor->name != NULL) { /* we're being probed by name */ if (ATX_StringsEqual(constructor->name, "WaveFormatter")) { /* our name */ *match = BLT_MODULE_PROBE_MATCH_EXACT; } else { /* not our name */ return BLT_FAILURE; } } else { /* we're probed by protocol/type specs only */ /* the output type should be audio/wav */ if (constructor->spec.output.media_type->id != self->wav_type_id) { return BLT_FAILURE; } *match = BLT_MODULE_PROBE_MATCH_MAX - 10; } ATX_LOG_FINE_1("WaveFormatterModule::Probe - Ok [%d]", *match); return BLT_SUCCESS; } break; default: break; } return BLT_FAILURE; }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_Activate +---------------------------------------------------------------------*/ BLT_METHOD OsxAudioUnitsOutput_Activate(BLT_MediaNode* _self, BLT_Stream* stream) { OsxAudioUnitsOutput* self = ATX_SELF_EX(OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode); ComponentResult result; AURenderCallbackStruct callback; BLT_COMPILER_UNUSED(stream); ATX_LOG_FINER("start"); /* select the device */ if (self->audio_device_id) { result = AudioUnitSetProperty(self->audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &self->audio_device_id, sizeof(self->audio_device_id)); if (result != noErr) { ATX_LOG_WARNING_1("AudioUnitSetProperty (kAudioOutputUnitProperty_CurrentDevice) failed (%d)", (int)result); } } /* initialize the output */ if (self->audio_unit) { result = AudioUnitInitialize(self->audio_unit); if (result != noErr) { ATX_LOG_WARNING_1("AudioUnitInitialize failed (%d)", (int)result); return BLT_FAILURE; } } /* set some default audio format */ { AudioStreamBasicDescription audio_desc; ATX_SetMemory(&audio_desc, 0, sizeof(audio_desc)); /* setup the audio description */ audio_desc.mFormatID = kAudioFormatLinearPCM; audio_desc.mFormatFlags = kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; audio_desc.mFramesPerPacket = 1; audio_desc.mSampleRate = 44100; audio_desc.mChannelsPerFrame = 2; audio_desc.mBitsPerChannel = 16; audio_desc.mBytesPerFrame = (audio_desc.mBitsPerChannel * audio_desc.mChannelsPerFrame) / 8; audio_desc.mBytesPerPacket = audio_desc.mBytesPerFrame * audio_desc.mFramesPerPacket; audio_desc.mReserved = 0; result = AudioUnitSetProperty(self->audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &audio_desc, sizeof(audio_desc)); if (result != noErr) { ATX_LOG_WARNING_1("AudioUnitSetProperty failed (%d)", (int)result); return BLT_FAILURE; } } /* check for downmix based on the number of supported channels */ OsxAudioUnitsOutput_CheckDownmix(self); /* setup the callback */ callback.inputProc = OsxAudioUnitsOutput_RenderCallback; callback.inputProcRefCon = _self; result = AudioUnitSetProperty(self->audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)); if (result != noErr) { ATX_LOG_SEVERE_1("AudioUnitSetProperty failed when setting callback (%d)", (int)result); return BLT_FAILURE; } 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; }
/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | 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; }