MPMediaItems необработанные данные песни - PullRequest
17 голосов
/ 01 ноября 2009

Мне было интересно, как получить доступ к необработанным данным MPMediaItem.

Есть идеи?

Ответы [ 3 ]

30 голосов
/ 10 октября 2010

Вы можете получить данные медиа-элемента следующим образом:

-(void)mediaItemToData
{
    // Implement in your project the media item picker

    MPMediaItem *curItem = musicPlayer.nowPlayingItem;

    NSURL *url = [curItem valueForProperty: MPMediaItemPropertyAssetURL];

    AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL: url options:nil];

    AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset: songAsset
                                       presetName: AVAssetExportPresetPassthrough];

    exporter.outputFileType = @"public.mpeg-4";

    NSString *exportFile = [[self myDocumentsDirectory] stringByAppendingPathComponent:           
                                                               @"exported.mp4"];

    NSURL *exportURL = [[NSURL fileURLWithPath:exportFile] retain];
    exporter.outputURL = exportURL; 

    // do the export
    // (completion handler block omitted) 
    [exporter exportAsynchronouslyWithCompletionHandler:
    ^{
    NSData *data = [NSData dataWithContentsOfFile: [[self myDocumentsDirectory] 
                                     stringByAppendingPathComponent: @"exported.mp4"]];

    // Do with data something

    }];
}

Этот код будет работать только на ios 4.0 и более поздних версиях

Удачи!

18 голосов
/ 12 декабря 2010

Конечно, вы можете получить доступ к данным MPMediaItem. Это не кристально ясно, но это работает. Вот как:

  • Получить URL медиа-элемента из его MPMediaItemPropertyAssetURL свойства
  • Инициализируйте AVURLAsset с этим URL
  • Инициализировать AVAssetReader с этим активом
  • Получите AVAssetTrack, который вы хотите прочитать из AVURLAsset
  • Создать AVAssetReaderTrackOutput с этим треком
  • Добавьте этот вывод к AVAssetReader, созданному ранее, и -startReading
  • Получить все данные с AVAssetReaderTrackOutput -copyNextSampleBuffer
  • PROFIT!

Вот пример кода из моего проекта (это не моя жемчужина кода, я написал его некоторое время назад, в мои темные времена):

typedef enum {
  kEDSupportedMediaTypeAAC = 'aac ',
  kEDSupportedMediaTypeMP3 = '.mp3'
} EDSupportedMediaType;

- (EDLibraryAssetReaderStatus)prepareAsset {
  // Get the AVURLAsset
  AVURLAsset *uasset = [m_asset URLAsset];

  // Check for DRM protected content
  if (uasset.hasProtectedContent) {
    return kEDLibraryAssetReader_TrackIsDRMProtected;
  }

  if ([uasset tracks] == 0) {
    DDLogError(@"no asset tracks found");
    return AVAssetReaderStatusFailed;
  }

  // Initialize a reader with a track output
  NSError *err = noErr;
  m_reader = [[AVAssetReader alloc] initWithAsset:uasset error:&err];
  if (!m_reader || err) {
    DDLogError(@"could not create asset reader (%i)\n", [err code]);
    return AVAssetReaderStatusFailed;
  }

  // Check tracks for valid format. Currently we only support all MP3 and AAC types, WAV and AIFF is too large to handle
  for (AVAssetTrack *track in uasset.tracks) {
    NSArray *formats = track.formatDescriptions;
    for (int i=0; i<[formats count]; i++) {
      CMFormatDescriptionRef format = (CMFormatDescriptionRef)[formats objectAtIndex:i];

      // Check the format types
      CMMediaType mediaType = CMFormatDescriptionGetMediaType(format);
      FourCharCode mediaSubType = CMFormatDescriptionGetMediaSubType(format);

      DDLogVerbose(@"mediaType: %s, mediaSubType: %s", COFcc(mediaType), COFcc(mediaSubType));
      if (mediaType == kCMMediaType_Audio) {
        if (mediaSubType == kEDSupportedMediaTypeAAC ||
            mediaSubType == kEDSupportedMediaTypeMP3) {
          m_track = [track retain];
          m_format = CFRetain(format);
          break;
        }
      }
    }
    if (m_track != nil && m_format != NULL) {
      break;
    }
  }

  if (m_track == nil || m_format == NULL) {
    return kEDLibraryAssetReader_UnsupportedFormat;
  }

  // Create an output for the found track
  m_output = [[AVAssetReaderTrackOutput alloc] initWithTrack:m_track outputSettings:nil];
  [m_reader addOutput:m_output];

  // Start reading
  if (![m_reader startReading]) {
    DDLogError(@"could not start reading asset");
    return kEDLibraryAssetReader_CouldNotStartReading;
  }

  return 0;
}

- (OSStatus)copyNextSampleBufferRepresentation:(CMSampleBufferRepresentationRef *)repOut {
  pthread_mutex_lock(&m_mtx);

  OSStatus err = noErr;
  AVAssetReaderStatus status = m_reader.status;

  if (m_invalid) {
    pthread_mutex_unlock(&m_mtx);
    return kEDLibraryAssetReader_Invalidated;
  }
  else if (status != AVAssetReaderStatusReading) {
    pthread_mutex_unlock(&m_mtx);
    return kEDLibraryAssetReader_NoMoreSampleBuffers;
  }

  // Read the next sample buffer
  CMSampleBufferRef sbuf = [m_output copyNextSampleBuffer];
  if (sbuf == NULL) {
    pthread_mutex_unlock(&m_mtx);
    return kEDLibraryAssetReader_NoMoreSampleBuffers;
  }

  CMSampleBufferRepresentationRef srep = CMSampleBufferRepresentationCreateWithSampleBuffer(sbuf);
  if (srep && repOut != NULL) {
    *repOut = srep;
  }
  else {
    DDLogError(@"CMSampleBufferRef corrupted");
    EDCFShow(sbuf);
    err = kEDLibraryAssetReader_BufferCorrupted;
  }
  CFRelease(sbuf);

  pthread_mutex_unlock(&m_mtx);

  return err;
}
0 голосов
/ 01 ноября 2009

Вы не можете, и нет обходного пути. MPMediaItem - это не фактический элемент мультимедиа, это просто метаданные об элементе мультимедиа, переданные приложению через RPC из другого процесса. Данные для самого элемента недоступны в вашем адресном пространстве.

Следует отметить, что даже если у вас есть MPMediaItem, его данные, вероятно, не загружаются в память устройства. Вспышка на iPhone медленная, а памяти мало. Хотя Apple может и не захотеть, чтобы у вас был доступ к необработанным данным, поддерживающим MPMediaItem, вполне вероятно, что они не удосужились заняться этим, поскольку не хотели тратить время, необходимое для работы с API. Если бы они предоставили доступ к такой вещи, это почти наверняка не было бы как NSData, но, скорее всего, как NSURL, они бы дали ваше приложение, которое позволило бы ему открывать файл и передавать данные.

В любом случае, если вам нужна функциональность, вы должны file сообщить об ошибке с запросом.

Кроме того, в качестве дополнительного примечания не указывайте свой возраст в отчете об ошибке, который вы отправляете в Apple. Я думаю, это очень здорово, что вы пишете приложения для телефона, когда я был в вашем возрасте, я любил экспериментировать с компьютерами (тогда я работал над вещами, написанными на Лиспе). Дело в том, что вы не можете юридически согласиться на контракт в Соединенных Штатах, поэтому соглашение о разработке специально запрещает вам присоединяться. Из первого абзаца соглашения :

Вы также подтверждаете, что являетесь совершеннолетие в юрисдикция, в которой вы проживаете (в не менее 18 лет во многих страны), и вы представляете, что вы юридически разрешено стать Зарегистрированный разработчик iPhone.

Если вы упомянете представителю WWDR, ​​что вы не достигли совершеннолетия, они могут осознать, что вы нарушаете соглашение, и обязаны закрыть свою учетную запись разработчика. Просто дружеское предупреждение.

...