MPMediaItems raw song data

前端 未结 3 1094
野性不改
野性不改 2020-11-29 17:40

I was wondering how to access an MPMediaItem\'s raw data.

Any ideas?

3条回答
  •  长情又很酷
    2020-11-29 18:13

    Of course you can access the data of a MPMediaItem. It's not crystal clear at once but it works. Here's how:

    • Get the media item's URL from it's MPMediaItemPropertyAssetURL property
    • Initialize an AVURLAsset with this URL
    • Initialize an AVAssetReader with this asset
    • Fetch the AVAssetTrack you want to read from the AVURLAsset
    • Create an AVAssetReaderTrackOutput with this track
    • Add this output to the AVAssetReader created before and -startReading
    • Fetch all data with AVAssetReaderTrackOutput's -copyNextSampleBuffer
    • PROFIT!

    Here is some sample code from a project of mine (this is not a code jewel of mine, wrote it some time back in my coding dark ages):

    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;
    }
    

提交回复
热议问题