libmtp关于MTP协议的实现

MTP协议中文翻译第一二三四章 阅读详情

我这里采用了1.1.7的libmtp。但其实计算机上实现这个协议的服务还有很多,而且还不一样。但理论上原理一样。

发送文件的流程

继续上一篇的逻辑。我在example里发现发送文件的协议逻辑。

int sendfile_function(char * from_path, char *to_path)
{
  filesize = sb.st_size;
  filename = basename(from_path);
  parent_id = parse_path (to_path,files,folders);
 
  LIBMTP_file_t *genfile;
  genfile = LIBMTP_new_file_t();
  genfile->filesize = filesize;
  genfile->filename = strdup(filename);
  genfile->filetype = find_filetype (filename);
  genfile->parent_id = parent_id;
  genfile->storage_id = 0;

  printf("Sending file...\n");
  ret = LIBMTP_Send_File_From_File(device, from_path, genfile, progress, NULL);

int LIBMTP_Send_File_From_File(LIBMTP_mtpdevice_t *device,
			       char const * const path, LIBMTP_file_t * const filedata,
			       LIBMTP_progressfunc_t const callback,
			       void const * const data)
{
  int fd;
  int ret;

  if ( (fd = open(path, O_RDONLY)) == -1) {

    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_File_From_File(): Could not open source file.");
    return -1;
  }
  ret = LIBMTP_Send_File_From_File_Descriptor(device, fd, filedata, callback, data);

int LIBMTP_Send_File_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
			 int const fd, LIBMTP_file_t * const filedata,
                         LIBMTP_progressfunc_t const callback,
			 void const * const data)
{
  uint16_t ret;
  PTPParams *params = (PTPParams *) device->params;
  PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
  LIBMTP_file_t *newfilemeta;
  int oldtimeout;
  int timeout;

  if (send_file_object_info(device, filedata))  //发送文件信息
  {
    // no need to output an error since send_file_object_info will already have done so
    return -1;
  }

  // Callbacks
  ptp_usb->callback_active = 1;
  // The callback will deactivate itself after this amount of data has been sent
  // One BULK header for the request, one for the data phase. No parameters to the request.
  ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
  ptp_usb->current_transfer_complete = 0;
  ptp_usb->current_transfer_callback = callback;
  ptp_usb->current_transfer_callback_data = data;

  /*
   * We might need to increase the timeout here, files can be pretty
   * large. Take the default timeout and add the calculated time for
   * this transfer
   */
  get_usb_device_timeout(ptp_usb, &oldtimeout);
  timeout = oldtimeout +
    (ptp_usb->current_transfer_total / guess_usb_speed(ptp_usb)) * 1000;
  set_usb_device_timeout(ptp_usb, timeout);

  ret = ptp_sendobject_fromfd(params, fd, filedata->filesize);   //发送文件

  ptp_usb->callback_active = 0;
  ptp_usb->current_transfer_callback = NULL;
  ptp_usb->current_transfer_callback_data = NULL;
  set_usb_device_timeout(ptp_usb, oldtimeout);

  if (ret == PTP_ERROR_CANCEL) {
    add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_File_Descriptor(): Cancelled transfer.");
    return -1;
  }
  if (ret != PTP_RC_OK) {
    add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_File_Descriptor(): "
				"Could not send object.");
    return -1;
  }

  add_object_to_cache(device, filedata->item_id);

  /*
   * Get the device-assigned parent_id from the cache.
   * The operation that adds it to the cache will
   * look it up from the device, so we get the new
   * parent_id from the cache.
   */
  newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
  if (newfilemeta != NULL) {
    filedata->parent_id = newfilemeta->parent_id;
    filedata->storage_id = newfilemeta->storage_id;
    LIBMTP_destroy_file_t(newfilemeta);
  } else {
    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
			    "LIBMTP_Send_File_From_File_Descriptor(): "
			    "Could not retrieve updated metadata.");
    return -1;
  }

  return 0;
}

再往下send_file_object_info就是发送的具体协议了。

    /*
     * MTP enhanched does it this way (from a sniff):
     * -> PTP_OC_MTP_SendObjectPropList (0x9808):
     *    20 00 00 00 01 00 08 98 1B 00 00 00 01 00 01 00
     *    FF FF FF FF 00 30 00 00 00 00 00 00 12 5E 00 00
     *    Length: 0x00000020
     *    Type:   0x0001 PTP_USB_CONTAINER_COMMAND
     *    Code:   0x9808
     *    Transaction ID: 0x0000001B
     *    Param1: 0x00010001 <- store
     *    Param2: 0xffffffff <- parent handle (-1 ?)
     *    Param3: 0x00003000 <- file type PTP_OFC_Undefined - we don't know about PDF files
     *    Param4: 0x00000000 <- file length MSB (-0x0c header len)
     *    Param5: 0x00005e12 <- file length LSB (-0x0c header len)
     *
     * -> PTP_OC_MTP_SendObjectPropList (0x9808):
     *    46 00 00 00 02 00 08 98 1B 00 00 00 03 00 00 00
     *    00 00 00 00 07 DC FF FF 0D 4B 00 53 00 30 00 36 - dc07 = file name
     *    00 30 00 33 00 30 00 36 00 2E 00 70 00 64 00 66
     *    00 00 00 00 00 00 00 03 DC 04 00 00 00 00 00 00 - dc03 = protection status
     *    00 4F DC 02 00 01                               - dc4f = non consumable
     *    Length: 0x00000046
     *    Type:   0x0002 PTP_USB_CONTAINER_DATA
     *    Code:   0x9808
     *    Transaction ID: 0x0000001B
     *    Metadata....
     *    0x00000003 <- Number of metadata items
     *    0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
     *    0xdc07     <- metadata type: file name
     *    0xffff     <- metadata type: string
     *    0x0d       <- number of (uint16_t) characters
     *    4b 53 30 36 30 33 30 36 2e 50 64 66 00 "KS060306.pdf", null terminated
     *    0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
     *    0xdc03     <- metadata type: protection status
     *    0x0004     <- metadata type: uint16_t
     *    0x0000     <- not protected
     *    0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
     *    0xdc4f     <- non consumable
     *    0x0002     <- metadata type: uint8_t
     *    0x01       <- non-consumable (this device cannot display PDF)
     *
     * <- Read 0x18 bytes back
     *    18 00 00 00 03 00 01 20 1B 00 00 00 01 00 01 00
     *    00 00 00 00 01 40 00 00
     *    Length: 0x000000018
     *    Type:   0x0003 PTP_USB_CONTAINER_RESPONSE
     *    Code:   0x2001 PTP_OK
     *    Transaction ID: 0x0000001B
     *    Param1: 0x00010001 <- store
     *    Param2: 0x00000000 <- parent handle
     *    Param3: 0x00004001 <- new file/object ID
     *
     * -> PTP_OC_SendObject (0x100d)
     *    0C 00 00 00 01 00 0D 10 1C 00 00 00
     * -> ... all the bytes ...
     * <- Read 0x0c bytes back
     *    0C 00 00 00 03 00 01 20 1C 00 00 00
     *    ... Then update metadata one-by one, actually (instead of sending it first!) ...
     */

/**
 * ptp_sendobjectinfo:
 * params:	PTPParams*
 *		uint32_t* store		- destination StorageID on Responder
 *		uint32_t* parenthandle 	- Parent ObjectHandle on responder
 * 		uint32_t* handle	- see Return values
 *		PTPObjectInfo* objectinfo- ObjectInfo that is to be sent
 * 
 * Sends ObjectInfo of file that is to be sent via SendFileObject.
 *
 * Return values: Some PTP_RC_* code.
 * Upon success : uint32_t* store	- Responder StorageID in which
 *					  object will be stored
 *		  uint32_t* parenthandle- Responder Parent ObjectHandle
 *					  in which the object will be stored
 *		  uint32_t* handle	- Responder's reserved ObjectHandle
 *					  for the incoming object
 **/
uint16_t
ptp_sendobjectinfo (PTPParams* params, uint32_t* store, 
			uint32_t* parenthandle, uint32_t* handle,
			PTPObjectInfo* objectinfo)
{
	uint16_t ret;
	PTPContainer ptp;
	unsigned char* oidata=NULL;
	uint32_t size;

	PTP_CNT_INIT(ptp);
	ptp.Code=PTP_OC_SendObjectInfo;
	ptp.Param1=*store;
	ptp.Param2=*parenthandle;
	ptp.Nparam=2;
	
	size=ptp_pack_OI(params, objectinfo, &oidata);
	ret = ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &oidata, NULL); 
	free(oidata);
	*store=ptp.Param1;
	*parenthandle=ptp.Param2;
	*handle=ptp.Param3; 
	return ret;
}
/* Transaction data phase description */
#define PTP_DP_NODATA		0x0000	/* no data phase */
#define PTP_DP_SENDDATA		0x0001	/* sending data */
#define PTP_DP_GETDATA		0x0002	/* receiving data */
#define PTP_DP_DATA_MASK	0x00ff	/* data phase mask */

/**
 * ptp_sendobject_fromfd:
 * params:	PTPParams*
 *		fd                      - File descriptor to read() object from
 *              uint64_t size           - File/object size
 *
 * Sends object from file descriptor by consecutive reads from this
 * descriptor.
 *
 * Return values: Some PTP_RC_* code.
 **/
uint16_t
ptp_sendobject_fromfd (PTPParams* params, int fd, uint64_t size)
{
	PTPContainer	ptp;
	PTPDataHandler	handler;
	uint16_t	ret;

	ptp_init_fd_handler (&handler, fd);
	PTP_CNT_INIT(ptp);
	ptp.Code=PTP_OC_SendObject;
	ptp.Nparam=0;
	ret = ptp_transaction_new(params, &ptp, PTP_DP_SENDDATA, size, &handler);
	ptp_exit_fd_handler (&handler);
	return ret;
}

读取文件

进行下对比

int LIBMTP_Get_File_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
					uint32_t const id,
					int const fd,
					LIBMTP_progressfunc_t const callback,
					void const * const data)
{
  uint16_t ret;
  PTPParams *params = (PTPParams *) device->params;
  PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
  PTPObject *ob;

  ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
  if (ret != PTP_RC_OK) {
    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
    return -1;
  }
  if (ob->oi.ObjectFormat == PTP_OFC_Association) {
    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
    return -1;
  }

  // Callbacks
  ptp_usb->callback_active = 1;
  ptp_usb->current_transfer_total = ob->oi.ObjectCompressedSize+
    PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
  ptp_usb->current_transfer_complete = 0;
  ptp_usb->current_transfer_callback = callback;
  ptp_usb->current_transfer_callback_data = data;

  ret = ptp_getobject_tofd(params, id, fd);

  ptp_usb->callback_active = 0;
  ptp_usb->current_transfer_callback = NULL;
  ptp_usb->current_transfer_callback_data = NULL;
ptp_object_want (PTPParams *params, uint32_t handle, unsigned int want, PTPObject **retob) {
	uint16_t	ret;
	PTPObject	*ob;
	/*Camera 		*camera = ((PTPData *)params->data)->camera;*/

	/* If GetObjectInfo is broken, force GetPropList */
	if (params->device_flags & DEVICE_FLAG_PROPLIST_OVERRIDES_OI)
		want |= PTPOBJECT_MTPPROPLIST_LOADED;

	*retob = NULL;
	if (!handle) {
		ptp_debug (params, "ptp_object_want: querying handle 0?\n");
		return PTP_RC_GeneralError;
	}
	ret = ptp_object_find_or_insert (params, handle, &ob);
	if (ret != PTP_RC_OK)
		return PTP_RC_GeneralError;
	*retob = ob;
	/* Do we have all of it already? */
	if ((ob->flags & want) == want)
		return PTP_RC_OK;

#define X (PTPOBJECT_OBJECTINFO_LOADED|PTPOBJECT_STORAGEID_LOADED|PTPOBJECT_PARENTOBJECT_LOADED)
	if ((want & X) && ((ob->flags & X) != X)) {
		uint32_t	saveparent = 0;
		
		/* One EOS issue, where getobjecthandles(root) returns obs without root flag. */
		if (ob->flags & PTPOBJECT_PARENTOBJECT_LOADED)
			saveparent = ob->oi.ParentObject;

		ret = ptp_getobjectinfo (params, handle, &ob->oi);
		if (ret != PTP_RC_OK) {
			/* kill it from the internal list ... */
			ptp_remove_object_from_cache(params, handle);
			return ret;
		}
uint16_t
ptp_getobjectinfo (PTPParams* params, uint32_t handle,
			PTPObjectInfo* objectinfo)
{
	uint16_t ret;
	PTPContainer ptp;
	unsigned char* oi=NULL;
	unsigned int len;

	PTP_CNT_INIT(ptp);
	ptp.Code=PTP_OC_GetObjectInfo;//  0x1008
	ptp.Param1=handle;
	ptp.Nparam=1;
	len=0;
	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &oi, &len);  //0x0002
	if (ret == PTP_RC_OK) ptp_unpack_OI(params, oi, objectinfo, len);
	free(oi);
	return ret;
}

三、协议公共 接口

/* Old style transaction, based on memory */
uint16_t
ptp_transaction (PTPParams* params, PTPContainer* ptp, 
		uint16_t flags, uint64_t sendlen,
		unsigned char **data, unsigned int *recvlen
) {
	PTPDataHandler	handler;
	uint16_t	ret;

	switch (flags & PTP_DP_DATA_MASK) {
	case PTP_DP_SENDDATA:
		ret = ptp_init_send_memory_handler (&handler, *data, sendlen);
		if (ret != PTP_RC_OK) return ret;
		break;
	case PTP_DP_GETDATA:
		ret = ptp_init_recv_memory_handler (&handler);
		if (ret != PTP_RC_OK) return ret;
		break;
	default:break;
	}
	ret = ptp_transaction_new (params, ptp, flags, sendlen, &handler);
	switch (flags & PTP_DP_DATA_MASK) {
	case PTP_DP_SENDDATA:
		ptp_exit_send_memory_handler (&handler);
		break;
	case PTP_DP_GETDATA: {
		unsigned long len;
		ptp_exit_recv_memory_handler (&handler, data, &len);
		if (recvlen)
			*recvlen = len;
		break;
	}
	default:break;
	}
	return ret;
}
/* PTP v1.0 operation codes */
#define PTP_OC_Undefined                0x1000
#define PTP_OC_GetDeviceInfo            0x1001
#define PTP_OC_OpenSession              0x1002
#define PTP_OC_CloseSession             0x1003
#define PTP_OC_GetStorageIDs            0x1004
#define PTP_OC_GetStorageInfo           0x1005
#define PTP_OC_GetNumObjects            0x1006
#define PTP_OC_GetObjectHandles         0x1007
#define PTP_OC_GetObjectInfo            0x1008
#define PTP_OC_GetObject                0x1009
#define PTP_OC_GetThumb                 0x100A
#define PTP_OC_DeleteObject             0x100B
#define PTP_OC_SendObjectInfo           0x100C
#define PTP_OC_SendObject               0x100D

这部分操作码和我在手机内核中看到的操作码虽然名称不一样,但功能基本是对应的。

struct _PTPContainer {
	uint16_t Code;
	uint32_t SessionID;
	uint32_t Transaction_ID;
	/* params  may be of any type of size less or equal to uint32_t */
	uint32_t Param1;
	uint32_t Param2;
	uint32_t Param3;
	/* events can only have three parameters */
	uint32_t Param4;
	uint32_t Param5;
	/* the number of meaningfull parameters */
	uint8_t	 Nparam;
};
typedef struct _PTPContainer PTPContainer;

这部分PTPContainer->code就是具体操作码

//文件信息
struct _PTPObjectInfo {
	uint32_t StorageID;
	uint16_t ObjectFormat;
	uint16_t ProtectionStatus;
	/* In the regular objectinfo this is 32bit,
	 * but we keep the general object size here
	 * that also arrives via other methods and so
	 * use 64bit */
	uint64_t ObjectCompressedSize;
	uint16_t ThumbFormat;
	uint32_t ThumbCompressedSize;
	uint32_t ThumbPixWidth;
	uint32_t ThumbPixHeight;
	uint32_t ImagePixWidth;
	uint32_t ImagePixHeight;
	uint32_t ImageBitDepth;
	uint32_t ParentObject;
	uint16_t AssociationType;
	uint32_t AssociationDesc;
	uint32_t SequenceNumber;
	char 	*Filename;
	time_t	CaptureDate;
	time_t	ModificationDate;
	char	*Keywords;
};
typedef struct _PTPObjectInfo PTPObjectInfo;

PTPParams* params属于设备信息

Android USB文件传输原理与MTP协议详解 USB文件传输是移动设备与计算机数据交互的基础功能,其核心协议MTP(Media Transfer Protocol)在Android系统中扮演关键角色。MTP协议基于PTP扩展,通过设备枚举、会话管理和分块传输机制实现高效文件操作,相比传统UMS模式具有不独占存储、支持文件系统无关性和元数据传输三大优势。从技术实现看,该功能涉及USB描述符协商、驱动加载和系统服务协同,典型应用场景包括媒体文件管理、开发调试和数据备份。通过分析USB配置描述符和MTP操作码,可以深入理解Android设备在‘设置>USB文 阅读详情

相关推荐

macOS 挂载 MTP 设备:从协议原理到 Moorage 实战

在跨平台设备协作中,文件系统的互操作性是常见难题。Android 手机通过 MTP(媒体传输协议)与电脑通信时,并不像 U 盘那样暴露块设备,而是以对象形式提供数据访问,这让 macOS 的原生文件系统机制无法直接识别。理解 MTP 的请求-响应模型、对象枚举与数据读写原理,是解决此类问题的关键。借助 FUSE(用户态文件系统)技术,macOS 可以将 MTP 设备挂载为本地路径,从而让 Finder、终端及各类脚本无缝操作手机文件。这种挂载能力不仅简化了 Android 设备的日常文件管理,还为自动化备份

weixin_29303701的博客 265

推荐开源项目:libmtp——强大的媒体传输协议库

推荐开源项目:libmtp——强大的媒体传输协议库 项目地址:https://gitcode.com/gh_mirrors/li/libmtp 项目介绍 libmtp 是一个开源的库,专门用于与MTP(Media Transfer Protocol)设备进行通信。它扮演了MTP发起者的角色,即通过USB接口与MTP响应者(如MP3播放器、智能手机等)建立会话。该项目源于对libptp2和libgp...

gitblog_00036的博客 1249

MTP 设备在 macOS 上的挂载与查看:Moorage 工具快速上手指南

在日常工程实践中,把安卓手机、微单相机等 MTP 设备连接到 macOS,往往比连接普通 U 盘更令人困惑。原因在于 MTP 协议并非将存储空间暴露为块设备,而是通过客户端与服务端对话的方式枚举文件和传输数据,macOS 也没有内置的通用挂载方案。理解这一原理后,才会明白为何 Finder 不显示、复制易中断、依赖 FUSE 或 libmtp 的挂载工具层出不穷。这类工具的真正价值,是把 MTP 设备映射为系统可访问的卷,从而让 rsync、find 等标准命令也能参与文件管理和批量导入。当面对大量照片、视

weixin_42651748的博客 246

在windows环境下,qt从mtp设备中获取文件

需求描述 1.在window中 2 使用qt 3从mtp设备中获取文件。 很显然这么奇葩的需求,肯定不是我自己想做的,没错的,你猜对了。是一个项目的需求。首先分析这个需求,我认为最难的一点就是基于window来做。(当然那些专业搞c#的人,整天研究大微软的人例外)。这个东西放在linux下简直太easy了。 ...

qq130106486的博客 2391

Android USB连接模式默认选为媒体传输协议(MTP)

Android设备支持多种USB连接模式,例如媒体传输协议(MTP)、图片传输协议(PTP)和USB存储模式等。综上所述,Android设备的USB连接模式默认选为媒体传输协议(MTP)。通过MTP模式,用户可以方便地在计算机上管理Android设备中的照片、音乐、视频等媒体文件,实现文件的传输和同步。完成上述步骤后,Android设备将被识别为可移动存储设备,可以在计算机的资源管理器或文件管理器中访问设备中的媒体文件。然后,在设备的通知栏中下拉,找到“USB用途”或“USB连接模式”的选项。

2301_79326891的博客 5318

MTP移植实战:libmtp在32位与64位嵌入式Linux下的交叉编译

USB传输协议家族中,MTP(Media Transfer Protocol)在PTP基础上扩展而来,专为媒体设备与主机间的对象传输设计。与UMS的块级访问不同,MTP由设备侧管理存储,主机通过协议栈操作对象,因此媒体设备厂商更青睐这种模式。在实际嵌入式Linux项目中,交叉编译libmtp常因32位与64位目标架构而受阻。理解MTP与libusb的底层关系,合理利用现成的移植工具包,能显著降低构建难度。通过sysroot隔离、pkg-config路径配置、架构校验等手段,可在同一宿主机产出双架构可交付产物

weixin_28729205的博客 215

USB与MTP协议关系解析

维度USB协议MTP协议关系说明协议定位传输层协议应用层协议MTP建立在USB之上核心功能提供数据传输通道定义媒体设备交互逻辑USB提供传输,MTP定义交互适用范围所有USB设备媒体传输设备MTP是USB的一个应用场景传输方式多种传输类型主要使用Bulk传输MTP选择USB的传输类型数据单位数据包(Packet)操作指令和数据对象USB数据包承载MTP消息。

inquisiter 1068

MTP 1.0协议规范详解与应用指南

MTP(Media Transfer Protocol)1.0协议诞生于21世纪初,旨在解决传统USB Mass Storage模式在移动设备普及背景下暴露的核心缺陷。该模式要求设备暴露底层文件系统,易导致主机直接写入引发文件系统损坏,尤其在未安全弹出时风险极高。MTP通过抽象存储结构,以“对象”为单位进行数据管理,避免了对FAT/FAT32等文件系统的直接依赖,提升了安全性与兼容性。其发展动因源于便携式媒体设备(如早期的Zune、Android手机、数码相机)对内容受控共享的迫切需求。

weixin_35750483的博客 1020

Go-mtpfs终极指南:如何通过FUSE轻松挂载Android设备

Go-mtpfs是一款简单的FUSE文件系统工具,专为将Android设备作为MTP设备挂载而设计。它能够快速挂载设备的所有存储区域,按需读取文件元数据,并且利用Android扩展实现部分数据读写,操作大文件时无需占用/tmp额外空间。 ## 🚀 为什么选择Go-mtpfs? Go-mtpfs采用纯Go语言实现MTP协议,基于libusb库开发,已在多款旗舰设备(如Galaxy Nexus、

gitblog_00985的博客 234

libmtp:访问 MTP 播放器的库(Mp3 播放器、Android 手机)-开源

libmtp 是媒体传输协议 (MTP) 的 LGPL 库实现,它是图片传输协议 (PTP) 的超集。

Veeam Backup & ONE download

前言 Veeam® Availability Suite™ 是 Veeam 的旗舰解决方案,可实现简单、灵活和可靠的数据管理。消除与数据保护、恢复、监控、勒索软件防护和合规性相关的手动流程,从而减轻数据维护压力。Veeam 能够帮助您节省时间和成本,同时支持您减少在备份方面花费的时间,将更多精力放在推动业务发展上。 Veeam Availability Suite Release 版本 包含 发布时间 复制磁力链接使用迅雷或者bittorrent ...

极致,细节 1999

android libmtp 编译,GitHub - libmtp/libmtp: A library to access MTP (Media Transfer Protocol) Devices....

Building and Installing-----------------------See the "INSTALL" file.Initiator and Responder-----------------------libmtp implements an MTP initiator, which means it initiateMTP sessions with devices....

weixin_39628063的博客 1326

数字IC后端设计实现 | PR工具中到底应该如何控制density和congestion?(ICC2&Innovus)

数字IC后端设计实现中到底应该如何控制cell density和congestion?(ICC2和Innovus两种解决方案)

weixin_37584728的博客 7113

android libmtp 编译,external_libmtp

Building and Installing-----------------------See the "INSTALL" file.Heritage--------libmtp is based on several ancestors:* libptp2 by Mariusz Woloszyn was the starting point usedby Richard A. Low for...

weixin_34614567的博客 907

利用Arcgis提取nc数据并计算区域年均温

1.下载数据。2.解压数据至不含中文的路径中。打开工具箱中的多维分析工具-创建NetCDF栅格图层,导入数据。3.打开工具箱中的数据管理工具-图层和表视图-创建栅格图层,导入数据,对输出数据进行命名,得到月均温栅格数据。4.选择工具箱-Spatial Analyst工具(空间分析工具)-地图代数-栅格计算器,计算全国一年年均温。​5.将其导出为.tif格式数据,方便后期使用。6.选择工具箱-Spatial Analyst工具(空间分析工具)-区域分析--以表格显示分区统计,得到分区域的气温数据。

什么都学亿点点的博客 7992

GNSS差分码偏差(DCB)从原理到实战:如何避免数据处理中的常见错误

本文深入解析GNSS差分码偏差(DCB)的原理及其对高精度定位的关键影响。针对数据处理中因忽略DCB校正导致的常见错误,如单系统PPP高程偏差、多系统融合精度下降及电离层研究失真等,提供了实战解决方案与主流DCB产品获取、集成方法,帮助用户有效规避陷阱,提升数据处理精度。

k5l6m的博客 224

libmtp 项目常见问题解决方案

libmtp 项目常见问题解决方案 项目基础介绍 libmtp 是一个用于访问 MTP(Media Transfer Protocol)设备的库。MTP 是一种用于在计算机和便携式设备(如数码相机、智能手机等)之间传输文件的协议。libmtp 项目的主要目的是提供一个跨平台的库,使得开发者能够轻松地在他们的应用程序中集成 MTP 设备的支持。 该项目主要使用 C 语言编写,依赖于 libusb 库...

gitblog_00540的博客 955

Python多版本共存指南:用CMD命令一键切换3.6和3.8解释器(含pip使用技巧)

本文详细介绍了在Windows CMD环境下实现Python多版本(如3.6和3.8)共存与一键切换的完整方案。通过文件重命名策略、环境变量优化和自定义脚本,开发者可快速切换Python解释器版本,并管理各版本独立的pip依赖库,确保项目环境隔离与兼容性。

weixin_29035405的博客 423

【亲测免费】 libmtp 项目推荐

libmtp 项目推荐 项目基础介绍和主要编程语言 libmtp 是一个开源的 C 语言库,专门用于访问 MTP(Media Transfer Protocol)设备。MTP 是一种用于在计算机和便携式媒体设备之间传输文件的协议。libmtp 提供了一个简单而强大的 API,使得开发者可以轻松地在他们的应用程序中集成 MTP 设备的支持。 项目核心功能 libmtp 的核心功能包括: MTP 设...

gitblog_00431的博客 497

SPD-Conv+YOLOv8:空间深度转换卷积赋能小目标检测,从原理到实战的科研级优化指南

从理解SPD-Conv“空间到深度+逐步卷积”的核心设计,到亲手将其嵌入YOLOv8并验证在小目标场景的表现,再到基于此探索属于自己的科研与工程方向——这个过程能让你深刻理解“小目标特征保留”在检测任务中的核心价值。现在就开始行动,相信你会在小目标检测的“细节捕捉”之路上,走出一条属于自己的技术路径。实验通常会证明:嵌入SPD-Conv后,YOLOv8在小目标AP上提升5-8个百分点,mAP50-95提升3-5个百分点,而推理速度仅下降5%以内,充分体现了其“保细节+提精度”的优势。

m0_64661770的博客 163

权重衰减weight_decay参数从入门到精通

Weight Decay是一个正则化技术,作用是**抑制模型的过拟合**,以此来提高模型的泛化性。 目前网上对于Weight Decay的讲解都比较泛,都是短短的几句话,但对于其原理、实现方式大多就没有讲解清楚,本文将会逐步解释weight decay机制。

iioSnail的博客 4万+

MTP模式与USB存储模式(MTP in Android)

转载:http://bbs.meizu.cn/thread-4747416-1-1.html MTP in Android MTP的全称是Media Transfer Protocol(媒体传输协议),它是微软公司提出的一套媒体文件传输协议。Android从3.0开始支持MTP。不过,在今天的智能手机领域内,Google和微软是一对冤家,为什么Android中会使用MTP呢?请看下文。 一 ...

ccyxchen的博客 3252

手把手教你学BSP(11.3)--BSP实例:基于Raspberry Pi 4 Model B的Linux BSP开发实例

通过以上步骤,我们完成了一个基于Raspberry Pi 4 Model B的Linux BSP开发过程,包括硬件初始化、设备驱动编写、Bootloader配置、内核配置和编译,以及最终映像的生成。每个步骤都非常重要,确保每一步都正确无误才能使整个系统正常运行。

MHD0815的博客 1011

【亲测免费】 libmtp 开源项目教程

libmtp 开源项目教程 1. 项目的目录结构及介绍 libmtp 是一个用于与 MTP(Media Transfer Protocol)设备进行通信的库。以下是项目的目录结构及其介绍: /src: 包含 libmtp 库的核心源代码文件。 /include: 包含 libmtp 的头文件,供其他程序引用。 /examples: 包含使用 libmtp 库的示例程序。 /tests: 包含测试...

gitblog_00542的博客 656

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

linux mtp 代码,Linux MTP 的故事

Linux下面有许许多多糟糕的故事,输入法算是其中之一,不过今天我们要讲的是另外一个故事。这个故事本质上和KDE关系不大,不过也算让我纠结了许久了。首先来介绍一下MTP,MTP是Media Transfer Protocol的缩写,由Microsoft设计并在Windows Media Player中引入,之前曾经有一个协议是PTP,缩写是Picture Transfer Protocol,PTP...

weixin_39974958的博客 1245

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

linux mtp设备,在Linux Mint 17.1中安装MTP Android设备

但是,当我点击“连接”时,我收到以下错误:Listing raw device(s)mtpfs: symbol lookup error: mtpfs: undefined symbol: LIBMTP_Detect_Raw_Devices解决方法:Linux Mint 17.1 Cinnamon 64位或最近的Ubuntu / Debian发行版.sudo apt-get updatesudo ...

weixin_42525551的博客 974

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

上一篇: MTP手机端实现过程
下一篇: lru算法
inquisiter
博客等级 码龄10年 374粉丝 228原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值