libmtp.c

来自「Media transfer protocol implementation o」· C语言 代码 · 共 2,016 行 · 第 1/5 页

C
2,016
字号
    free(track->album);  if (track->genre != NULL)    free(track->genre);  if (track->date != NULL)    free(track->date);  if (track->filename != NULL)    free(track->filename);  free(track);  return;}/** * This function retrieves the track metadata for a track * given by a unique ID. * @param device a pointer to the device to get the track metadata off. * @param trackid the unique ID of the track. * @param objectformat the object format of this track, so we know what it supports. * @param track a metadata set to fill in. */static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,			       LIBMTP_track_t *track){  uint16_t ret;  PTPParams *params = (PTPParams *) device->params;  PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;  uint32_t i;#ifdef ENABLE_MTP_ENHANCED  if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)      && !(ptp_usb->device_flags & DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST)) {    MTPPropList *proplist = NULL;    MTPPropList *prop;    MTPPropList *tmpprop;    /*     * This should retrieve all properties for an object, but on devices     * which are inherently broken it will not, so these need the     * special flag DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST.     */    ret = ptp_mtp_getobjectproplist(params, track->item_id, &proplist);    prop = proplist;    while (prop != NULL) {      switch (prop->property) {      case PTP_OPC_Name:	if (prop->propval.str != NULL)	  track->title = strdup(prop->propval.str);	else	  track->title = NULL;	break;      case PTP_OPC_Artist:	if (prop->propval.str != NULL)	  track->artist = strdup(prop->propval.str);	else	  track->artist = NULL;	break;      case PTP_OPC_Duration:	track->duration = prop->propval.u32;	break;      case PTP_OPC_Track:	track->tracknumber = prop->propval.u16;	break;      case PTP_OPC_Genre:	if (prop->propval.str != NULL)	  track->genre = strdup(prop->propval.str);	else	  track->genre = NULL;	break;      case PTP_OPC_AlbumName:	if (prop->propval.str != NULL)	  track->album = strdup(prop->propval.str);	else	  track->album = NULL;	break;      case PTP_OPC_OriginalReleaseDate:	if (prop->propval.str != NULL)	  track->date = strdup(prop->propval.str);	else	  track->date = NULL;	break;	// These are, well not so important.      case PTP_OPC_SampleRate:	track->samplerate = prop->propval.u32;	break;      case PTP_OPC_NumberOfChannels:	track->nochannels = prop->propval.u16;	break;      case PTP_OPC_AudioWAVECodec:	track->wavecodec = prop->propval.u32;	break;      case PTP_OPC_AudioBitRate:	track->bitrate = prop->propval.u32;	break;      case PTP_OPC_BitRateType:	track->bitratetype = prop->propval.u16;	break;      case PTP_OPC_Rating:	track->rating = prop->propval.u16;	break;      case PTP_OPC_UseCount:	track->usecount = prop->propval.u32;	break;      }      tmpprop = prop;      prop = prop->next;      Destroy_MTP_Prop_Entry(tmpprop);    }  } else {#else  {#endif    uint16_t *props = NULL;    uint32_t propcnt = 0;    // First see which properties can be retrieved for this object format    ret = ptp_mtp_getobjectpropssupported (params, map_libmtp_type_to_ptp_type(track->filetype), &propcnt, &props);    if (ret != PTP_RC_OK) {      // Just bail out for now, nothing is ever set.      return;    } else {      for (i=0;i<propcnt;i++) {	switch (props[i]) {	case PTP_OPC_Name:	  track->title = get_string_from_object(device, track->item_id, PTP_OPC_Name);	  break;	case PTP_OPC_Artist:	  track->artist = get_string_from_object(device, track->item_id, PTP_OPC_Artist);	  break;	case PTP_OPC_Duration:	  track->duration = get_u32_from_object(device, track->item_id, PTP_OPC_Duration, 0);	  break;	case PTP_OPC_Track:	  track->tracknumber = get_u16_from_object(device, track->item_id, PTP_OPC_Track, 0);	  break;	case PTP_OPC_Genre:	  track->genre = get_string_from_object(device, track->item_id, PTP_OPC_Genre);	  break;	case PTP_OPC_AlbumName:	  track->album = get_string_from_object(device, track->item_id, PTP_OPC_AlbumName);	  break;	case PTP_OPC_OriginalReleaseDate:	  track->date = get_string_from_object(device, track->item_id, PTP_OPC_OriginalReleaseDate);	  break;	  // These are, well not so important.	case PTP_OPC_SampleRate:	  track->samplerate = get_u32_from_object(device, track->item_id, PTP_OPC_SampleRate, 0);	  break;	case PTP_OPC_NumberOfChannels:	  track->nochannels = get_u16_from_object(device, track->item_id, PTP_OPC_NumberOfChannels, 0);	  break;	case PTP_OPC_AudioWAVECodec:	  track->wavecodec = get_u32_from_object(device, track->item_id, PTP_OPC_AudioWAVECodec, 0);	  break;	case PTP_OPC_AudioBitRate:	  track->bitrate = get_u32_from_object(device, track->item_id, PTP_OPC_AudioBitRate, 0);	  break;	case PTP_OPC_BitRateType:	  track->bitratetype = get_u16_from_object(device, track->item_id, PTP_OPC_BitRateType, 0);	  break;	case PTP_OPC_Rating:	  track->rating = get_u16_from_object(device, track->item_id, PTP_OPC_Rating, 0);	  break;	case PTP_OPC_UseCount:	  track->usecount = get_u32_from_object(device, track->item_id, PTP_OPC_UseCount, 0);	  break;	}      }      free(props);    }  }}/** * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER * NOT TO USE IT. * @see LIBMTP_Get_Tracklisting_With_Callback() */LIBMTP_track_t *LIBMTP_Get_Tracklisting(LIBMTP_mtpdevice_t *device){  printf("WARNING: LIBMTP_Get_Tracklisting() is deprecated.\n");  printf("WARNING: please update your code to use LIBMTP_Get_Tracklisting_With_Callback()\n");  return LIBMTP_Get_Tracklisting_With_Callback(device, NULL, NULL);}/** * This returns a long list of all tracks available * on the current MTP device. Typical usage: * * <pre> * LIBMTP_track_t *tracklist; * * tracklist = LIBMTP_Get_Tracklisting(device, callback, data); * while (tracklist != NULL) { *   LIBMTP_track_t *tmp; * *   // Do something on each element in the list here... *   tmp = tracklist; *   tracklist = tracklist->next; *   LIBMTP_destroy_track_t(tmp); * } * </pre> * * @param device a pointer to the device to get the track listing for. * @param callback a function to be called during the tracklisting retrieveal *               for displaying progress bars etc, or NULL if you don't want *               any callbacks. * @param data a user-defined pointer that is passed along to *             the <code>progress</code> function in order to *             pass along some user defined data to the progress *             updates. If not used, set this to NULL. * @return a list of tracks that can be followed using the <code>next</code> *         field of the <code>LIBMTP_track_t</code> data structure. *         Each of the metadata tags must be freed after use, and may *         contain only partial metadata information, i.e. one or several *         fields may be NULL or 0. * @see LIBMTP_Get_Trackmetadata() */LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t *device,                                                      LIBMTP_progressfunc_t const callback,                                                      void const * const data){  uint32_t i = 0;  LIBMTP_track_t *retracks = NULL;  LIBMTP_track_t *curtrack = NULL;  PTPParams *params = (PTPParams *) device->params;  // Get all the handles if we haven't already done that  if (params->handles.Handler == NULL) {    flush_handles(device);  }  for (i = 0; i < params->handles.n; i++) {    if (callback != NULL)      callback(i, params->handles.n, data);    LIBMTP_track_t *track;    PTPObjectInfo oi;    if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {      // Ignore stuff we don't know how to handle...      // TODO: get this list as an intersection of the sets      // supported by the device and the from the device and      // all known audio track files?      if ( oi.ObjectFormat != PTP_OFC_WAV &&	   oi.ObjectFormat != PTP_OFC_MP3 &&	   oi.ObjectFormat != PTP_OFC_MTP_WMA &&	   oi.ObjectFormat != PTP_OFC_MTP_OGG &&	   oi.ObjectFormat != PTP_OFC_MTP_MP4 &&	   oi.ObjectFormat != PTP_OFC_MTP_UndefinedAudio ) {	// printf("Not a music track (format: %d), skipping...\n",oi.ObjectFormat);	continue;      }      // Allocate a new track type      track = LIBMTP_new_track_t();      // This is some sort of unique ID so we can keep track of the track.      track->item_id = params->handles.Handler[i];      track->parent_id = oi.ParentObject;      track->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);      // Original file-specific properties      track->filesize = oi.ObjectCompressedSize;      if (oi.Filename != NULL) {	track->filename = strdup(oi.Filename);      }      get_track_metadata(device, oi.ObjectFormat, track);      // Add track to a list that will be returned afterwards.      if (retracks == NULL) {	retracks = track;	curtrack = track;      } else {	curtrack->next = track;	curtrack = track;      }      // Call listing callback      // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;    } else {      printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");    }  } // Handle counting loop  return retracks;}/** * This function retrieves the metadata for a single track off * the device. * * Do not call this function repeatedly! The track handles are linearly * searched O(n) and the call may involve (slow) USB traffic, so use * <code>LIBMTP_Get_Tracklisting()</code> and cache the tracks, preferably * as an efficient data structure such as a hash list. * * @param device a pointer to the device to get the track metadata from. * @param trackid the object ID of the track that you want the metadata for. * @return a track metadata entry on success or NULL on failure. * @see LIBMTP_Get_Tracklisting() */LIBMTP_track_t *LIBMTP_Get_Trackmetadata(LIBMTP_mtpdevice_t *device, uint32_t const trackid){  uint32_t i = 0;  PTPParams *params = (PTPParams *) device->params;  // Get all the handles if we haven't already done that  if (params->handles.Handler == NULL) {    flush_handles(device);  }  for (i = 0; i < params->handles.n; i++) {    PTPObjectInfo oi;    // Skip if this is not the track we want.    if (params->handles.Handler[i] != trackid) {      continue;    }    if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {      LIBMTP_track_t *track;      // Ignore stuff we don't know how to handle...      if ( oi.ObjectFormat != PTP_OFC_WAV &&	   oi.ObjectFormat != PTP_OFC_MP3 &&	   oi.ObjectFormat != PTP_OFC_MTP_WMA &&	   oi.ObjectFormat != PTP_OFC_MTP_OGG &&	   oi.ObjectFormat != PTP_OFC_MTP_MP4 &&	   oi.ObjectFormat != PTP_OFC_MTP_UndefinedAudio ) {	return NULL;      }      // Allocate a new track type      track = LIBMTP_new_track_t();      // This is some sort of unique ID so we can keep track of the track.      track->item_id = params->handles.Handler[i];      track->parent_id = oi.ParentObject;      track->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);      // Original file-specific properties      track->filesize = oi.ObjectCompressedSize;      if (oi.Filename != NULL) {	track->filename = strdup(oi.Filename);      }      get_track_metadata(device, oi.ObjectFormat, track);      return track;    } else {      return NULL;    }  }  return NULL;}/** * This gets a file off the device to a local file identified * by a filename. * @param device a pointer to the device to get the track from. * @param id the file ID of the file to retrieve. * @param path a filename to use for the retrieved file. * @param callback a progress indicator function or NULL to ignore. * @param data a user-defined pointer that is passed along to *             the <code>progress</code> function in order to *             pass along some user defined data to the progress *             updates. If not used, set this to NULL. * @return 0 if the transfer was successful, any other value means *           failure. * @see LIBMTP_Get_File_To_File_Descriptor() */int LIBMTP_Get_File_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,			 char const * const path, LIBMTP_progressfunc_t const callback,			 void const * const data){  int fd = -1;  int ret;  // Sanity check  if (path == NULL) {    printf("LIBMTP_Get_File_To_File(): Bad arguments, path was NULL\n");    return -1;  }  // Open file#ifdef __WIN32__#ifdef USE_WINDOWS_IO_H  if ( (fd = _open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,_S_IREAD)) == -1 ) {#else  if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,S_IRWXU|S_IRGRP)) == -1 ) {#endif#else

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?