MPMediaItems raw song data
Asked Answered
C

3

18

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

Any ideas?

Conventioneer answered 1/11, 2009 at 1:41 Comment(1)
how to get nsdata of mp3 using MPMediaPilau
H
30

you can obtain the media item's data in such way:

-(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

    }];
}

This code will work only on ios 4.0 and later

Good luck!

Hypesthesia answered 10/10, 2010 at 9:53 Comment(7)
i try this code in ios 4.0 but it not work there below is source of codeGlass
This solution is way to complicated, have a look at mine below (you don't need an export session for this).Lemmon
@Michalel i am getting data null in ios6. is there any property set in app to export ?? or any other setting required for this code ? please suggest me for the sameGeryon
Switch AVAssetExportPresetPassthrough to AVAssetExportPresetAppleM4A for preset. That fixed it for meDisenthrone
while choosing AVAssetExportPresetAppleM4A it is showing 'Invalid output file type' other wise it is showing null.Certificate
MPMediaItemPropertyAssetURL is returning null on iOS6+, any ideas?Corvin
Same here, showing Invalid output file type when using AVAssetExportPresetAppleM4A any solution?Peru
L
19

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;
}
Lemmon answered 12/12, 2010 at 20:32 Comment(2)
@ErikAigner i am able to list songs in nslog using Media Picker.. But i want to play those songs with my player ( Coded using Avplayer). How can i play both songsBillboard
MPMediaItemPropertyAssetURL returns null, any ideas on a work around?Corvin
L
-2

You can't, and there are no workaround. An MPMediaItem is not the actual piece of media, it is just the metadata about the media item communicated to the application via RPC from another process. The data for the item itself is not accessible in your address space.

I should note that even if you have the MPMediaItem its data probably is not loaded into the devices memory. The flash on the iPhone is slow and memory is scarce. While Apple may not want you to have access to the raw data backing an MPMediaItem, it is just as likely that they didn't bother dealing with it because they didn't want to invest the time necessary to deal with the APIs. If they did provide access to such a thing it almost certainly would not be as an NSData, but more likely as an NSURL they would give your application that would allow it to open the file and stream through the data.

In any event, if you want the functionality, you should file a bug report asking for.

Also, as a side note, don't mention your age in a bug report you send to Apple. I think it is very cool you are writing apps for the phone, when I was your age I loved experimenting with computers (back then I was working on things written in Lisp). The thing is you cannot legally agree to a contract in the United States, which is why the developer agreement specifically prohibits you from joining. From the first paragraph of the agreement:

You also certify that you are of the legal age of majority in the jurisdiction in which you reside (at least 18 years of age in many countries) and you represent that you are legally permitted to become a Registered iPhone Developer.

If you mention to a WWDR representative that you are not of age of majority they may realize you are in violation of the agreement and be obligated to terminate your developer account. Just a friendly warning.

Lethalethal answered 1/11, 2009 at 5:49 Comment(2)
My dad did all that stuff and technically, He's the iPhone Developer, so it's all goodConventioneer
It might have been correct at the time of the writing (2009). But now in 2017 there is an API for that and the answer is at least obsolete (if it were correct in 2009 : i'm not an avfoundation historian, I don't remember if there was an AVAssetExportSession back in Nov 2009)Hembree

© 2022 - 2024 — McMap. All rights reserved.