libmtp.c
来自「Media transfer protocol implementation o」· C语言 代码 · 共 2,016 行 · 第 1/5 页
C
2,016 行
* @param attribute_id PTP attribute ID * @param value_default Default value to return on failure * @return a value */static uint8_t get_u8_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id, uint16_t const attribute_id, uint8_t const value_default){ PTPPropertyValue propval; uint8_t retval = value_default; PTPParams *params = (PTPParams *) device->params; uint16_t ret; if ( device == NULL ) { return value_default; } ret = ptp_mtp_getobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT8); if (ret == PTP_RC_OK) { retval = propval.u8; } return retval;}/** * Sets an object attribute from a string * * @param device a pointer to an MTP device. * @param object_id Object reference * @param attribute_id PTP attribute ID * @param string string value to set * @return 0 on success, any other value means failure */static int set_object_string(LIBMTP_mtpdevice_t *device, uint32_t const object_id, uint16_t const attribute_id, char const * const string){ PTPPropertyValue propval; PTPParams *params = (PTPParams *) device->params; uint16_t ret; if (device == NULL || string == NULL) { return -1; } propval.str = (char *) string; ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR); if (ret != PTP_RC_OK) { printf("set_object_string(): could not set object string.\n"); printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret); return -1; } return 0;}/** * Sets an object attribute from an unsigned 32-bit integer * * @param device a pointer to an MTP device. * @param object_id Object reference * @param attribute_id PTP attribute ID * @param value 32-bit unsigned integer to set * @return 0 on success, any other value means failure */static int set_object_u32(LIBMTP_mtpdevice_t *device, uint32_t const object_id, uint16_t const attribute_id, uint32_t const value){ PTPPropertyValue propval; PTPParams *params = (PTPParams *) device->params; uint16_t ret; if (device == NULL) { return -1; } propval.u32 = value; ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT32); if (ret != PTP_RC_OK) { printf("set_object_u32(): could not set unsigned 32bit integer property.\n"); printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret); return -1; } return 0;}/** * Sets an object attribute from an unsigned 16-bit integer * * @param device a pointer to an MTP device. * @param object_id Object reference * @param attribute_id PTP attribute ID * @param value 16-bit unsigned integer to set * @return 0 on success, any other value means failure */static int set_object_u16(LIBMTP_mtpdevice_t *device, uint32_t const object_id, uint16_t const attribute_id, uint16_t const value){ PTPPropertyValue propval; PTPParams *params = (PTPParams *) device->params; uint16_t ret; if (device == NULL) { return 1; } propval.u16 = value; ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT16); if (ret != PTP_RC_OK) { printf("set_object_u16(): could not set unsigned 16bit integer property.\n"); printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret); return 1; } return 0;}/** * Sets an object attribute from an unsigned 8-bit integer * * @param device a pointer to an MTP device. * @param object_id Object reference * @param attribute_id PTP attribute ID * @param value 8-bit unsigned integer to set * @return 0 on success, any other value means failure */static int set_object_u8(LIBMTP_mtpdevice_t *device, uint32_t const object_id, uint16_t const attribute_id, uint8_t const value){ PTPPropertyValue propval; PTPParams *params = (PTPParams *) device->params; uint16_t ret; if (device == NULL) { return 1; } propval.u8 = value; ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT8); if (ret != PTP_RC_OK) { printf("set_object_u8(): could not set unsigned 8bit integer property.\n"); printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret); return 1; } return 0;}/** * Get a list of the supported devices. * * The developers depend on users of this library to constantly * add in to the list of supported devices. What we need is the * device name, USB Vendor ID (VID) and USB Product ID (PID). * put this into a bug ticket at the project homepage, please. * The VID/PID is used to let e.g. udev lift the device to * console userspace access when it's plugged in. * * @param devices a pointer to a pointer that will hold a device * list after the call to this function, if it was * successful. * @param numdevs a pointer to an integer that will hold the number * of devices in the device list if the call was successful. * @return 0 if the list was successfull retrieved, any other * value means failure. */int LIBMTP_Get_Supported_Devices_List(LIBMTP_device_entry_t ** const devices, int * const numdevs){ // Just dispatch to libusb glue file... return get_device_list(devices, numdevs);}/** * Get the first connected MTP device. There is currently no API for * retrieveing multiple devices. * @return a device pointer. */LIBMTP_mtpdevice_t *LIBMTP_Get_First_Device(void){ uint8_t interface_number; PTPParams *params; PTP_USB *ptp_usb; PTPStorageIDs storageIDs; uint32_t storageID = 0; PTPDevicePropDesc dpd; uint8_t batteryLevelMax = 100; // Some default uint16_t ret; uint32_t i; LIBMTP_mtpdevice_t *tmpdevice; uint8_t remaining_directories; // Allocate a parameter block params = (PTPParams *) malloc(sizeof(PTPParams)); params->cd_locale_to_ucs2 = iconv_open(UCS_2_INTERNAL, "UTF-8"); params->cd_ucs2_to_locale = iconv_open("UTF-8", UCS_2_INTERNAL); if (params->cd_locale_to_ucs2 == (iconv_t) -1 || params->cd_ucs2_to_locale == (iconv_t) -1) { printf("LIBMTP panic: could not open iconv() converters to/from UCS-2!\n"); return NULL; } ptp_usb = (PTP_USB *) malloc(sizeof(PTP_USB)); // Callbacks and stuff ptp_usb->callback_active = 0; ptp_usb->current_transfer_total = 0; ptp_usb->current_transfer_complete = 0; ptp_usb->current_transfer_callback = NULL; // get storage ID ret = connect_first_device(params, ptp_usb, &interface_number); switch (ret) { case PTP_CD_RC_CONNECTED: printf("Connected to MTP device.\n"); break; case PTP_CD_RC_NO_DEVICES: printf("No MTP devices.\n"); return NULL; case PTP_CD_RC_ERROR_CONNECTING: printf("Connection error.\n"); return NULL; } // get storage ID if (ptp_getstorageids (params, &storageIDs) == PTP_RC_OK) { if (storageIDs.n > 0) storageID = storageIDs.Storage[0]; free(storageIDs.Storage); } // Make sure there are no handlers params->handles.Handler = NULL; // Just cache the device information for any later use. if (ptp_getdeviceinfo(params, ¶ms->deviceinfo) != PTP_RC_OK) { goto error_handler; } // Get battery maximum level if (ptp_property_issupported(params, PTP_DPC_BatteryLevel)) { if (ptp_getdevicepropdesc(params, PTP_DPC_BatteryLevel, &dpd) != PTP_RC_OK) { printf("LIBMTP_Get_First_Device(): Unable to retrieve battery max level.\n"); goto error_handler; } // if is NULL, just leave as default if (dpd.FORM.Range.MaximumValue.u8 != 0) { batteryLevelMax = dpd.FORM.Range.MaximumValue.u8; } ptp_free_devicepropdesc(&dpd); } // OK everything got this far, so it is time to create a device struct! tmpdevice = (LIBMTP_mtpdevice_t *) malloc(sizeof(LIBMTP_mtpdevice_t)); tmpdevice->interface_number = interface_number; tmpdevice->params = (void *) params; tmpdevice->usbinfo = (void *) ptp_usb; tmpdevice->storage_id = storageID; tmpdevice->maximum_battery_level = batteryLevelMax; // Set all default folders to 0 == root directory tmpdevice->default_music_folder = 0; tmpdevice->default_playlist_folder = 0; tmpdevice->default_picture_folder = 0; tmpdevice->default_video_folder = 0; tmpdevice->default_organizer_folder = 0; tmpdevice->default_zencast_folder = 0; tmpdevice->default_album_folder = 0; /* * Then get the handles and try to locate the default folders. * This has the desired side effect of cacheing all handles from * the device which speeds up later operations. */ flush_handles(tmpdevice); /* * Remaining directories to get the handles to. * We can stop when done this to save time */ remaining_directories = 7; for (i = 0; i < params->handles.n && remaining_directories > 0; i++) { PTPObjectInfo oi; if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) { // Ignore non-folders if ( oi.ObjectFormat != PTP_OFC_Association ) continue; if ( oi.Filename == NULL) continue; if (!strcmp(oi.Filename, "Music")) { tmpdevice->default_music_folder = params->handles.Handler[i]; remaining_directories--; continue; } else if ((!strcmp(oi.Filename, "My Playlists")) || (!strcmp(oi.Filename, "Playlists"))) { tmpdevice->default_playlist_folder = params->handles.Handler[i]; remaining_directories--; continue; } else if (!strcmp(oi.Filename, "Pictures")) { tmpdevice->default_picture_folder = params->handles.Handler[i]; remaining_directories--; continue; } else if (!strcmp(oi.Filename, "Video")) { tmpdevice->default_video_folder = params->handles.Handler[i]; remaining_directories--; continue; } else if (!strcmp(oi.Filename, "My Organizer")) { tmpdevice->default_organizer_folder = params->handles.Handler[i]; remaining_directories--; continue; } else if (!strcmp(oi.Filename, "ZENcast")) { tmpdevice->default_zencast_folder = params->handles.Handler[i]; remaining_directories--; continue; } else if (!strcmp(oi.Filename, "Albums")) { tmpdevice->default_album_folder = params->handles.Handler[i]; remaining_directories--; continue; } } else { printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n"); } } return tmpdevice; // Then close it again. error_handler: close_device(ptp_usb, params, interface_number); // TODO: libgphoto2 does not seem to be able to free the deviceinfo // ptp_free_deviceinfo(¶ms->deviceinfo); if (params->handles.Handler != NULL) { free(params->handles.Handler); } return NULL;}/** * This closes and releases an allocated MTP device. * @param device a pointer to the MTP device to release. */void LIBMTP_Release_Device(LIBMTP_mtpdevice_t *device){ PTPParams *params = (PTPParams *) device->params; PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo; close_device(ptp_usb, params, device->interface_number); // Free the device info and any handler // TODO: libgphoto2 does not seem to be able to free the deviceinfo // ptp_free_deviceinfo(¶ms->deviceinfo); if (params->handles.Handler != NULL) { free(params->handles.Handler); params->handles.Handler = NULL; } // Free iconv() converters... iconv_close(params->cd_locale_to_ucs2); iconv_close(params->cd_ucs2_to_locale); free(device);}/** * This function refresh the internal handle list whenever * the items stored inside the device is altered. On operations * that do not add or remove objects, this is typically not * called. * @param device a pointer to the MTP device to flush handles for. */static void flush_handles(LIBMTP_mtpdevice_t *device){ PTPParams *params = (PTPParams *) device->params; uint16_t ret; if (params->handles.Handler != NULL) { free(params->handles.Handler); } // Get all the handles if we haven't already done that ret = ptp_getobjecthandles(params, PTP_GOH_ALL_STORAGE, PTP_GOH_ALL_FORMATS, PTP_GOH_ALL_ASSOCS, ¶ms->handles); if (ret != PTP_RC_OK) { printf("flush_handles(): LIBMTP panic: Could not get object handles...\n"); printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret); } return;}/** * This function dumps out a large chunk of textual information * provided from the PTP protocol and additionally some extra * MTP-specific information where applicable. * @param device a pointer to the MTP device to report info from. */void LIBMTP_Dump_Device_Info(LIBMTP_mtpdevice_t *device){ int i; PTPParams *params = (PTPParams *) device->params; PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo; printf("USB low-level info:\n");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?