Reading video metadata on iOS 7 - always empty - ios

I am exporting a Quicktime video using AVExporterSession and setting the metadata on it as follows:
AVMutableMetadataItem *newMetaDataCommentItem = [[AVMutableMetadataItem alloc] init];
[newMetaDataCommentItem setKeySpace:AVMetadataKeySpaceQuickTimeMetadata];
[newMetaDataCommentItem setKey:AVMetadataQuickTimeMetadataKeyComment];
[newMetaDataCommentItem setValue:#"Test metadata value"];
NSMutableArray *metaData = [NSMutableArray array];
[metaData addObject:newMetaDataCommentItem];
exporter = [[AVAssetExportSession alloc] initWithAsset:mutableComposition
presetName:AVAssetExportPresetHighestQuality];
exporter.outputURL=[[SNMovieManager instance] urlForFinalMovie];
exporter.metadata = metaData;
exporter.outputFileType = AVFileTypeQuickTimeMovie;
exporter.shouldOptimizeForNetworkUse = YES;
exporter.videoComposition = video;
I then import the file video to my Mac and run mdls on it and see the value has been set correctly: kMDItemComment = "Test metadata value"
The bit I can't do is read that value back. I am using the following to read the file. The asset is correct but the metadata property is always an empty dictionary.
[group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if([[result valueForProperty:#"ALAssetPropertyType"] isEqualToString:#"ALAssetTypeVideo"])
{
ALAssetRepresentation *rep = result.defaultRepresentation;
NSDictionary *metadata = rep.metadata;
[images addObject:(id)rep.fullScreenImage];
}
Does anyone know if I am taking the correct approach here and if not let me know what the correct approach to read this comment back out is?
Thanks
Simon

I would be highly appreciated if you can provide more code base related to the PhotoLibrary save process.
Otherwise only one answer, Metadata will return nil if the representation is one that the system cannot interpret.
The returned dictionary holds the properties of the video at a specified location in an file source.

I'think your problem is on getting metadata script
You should get an AVURLAsset first and get metadata from it ALAssetRepresentation metadata is different
[group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if([[result valueForProperty:#"ALAssetPropertyType"] isEqualToString:#"ALAssetTypeVideo"])
{
AVURLAsset *videoAset = [AVURLAsset assetWithURL:[[asset defaultRepresentation] url]];
if ([[videoAset metadataForFormat:AVMetadataFormatQuickTimeMetadata] count]) {
AVMutableMetadataItem *meta = [[videoAset metadataForFormat:AVMetadataFormatQuickTimeUserData] objectAtIndex:0];
NSLog(#"%#",meta);
NSLog(#"%lu",(unsigned long)[[videoAset metadataForFormat:AVMetadataFormatQuickTimeMetadata] count]);
}
}

Related

Not able to find the DPI for an image in iOS

I want to find the DPI for an image that has been captured from iPhone/iPad Camera
this is how i am trying to get the DPI
CFDictionaryRef exifDict = CMGetAttachment(imageDataSampleBuffer,
kCGImagePropertyExifDictionary ,
NULL);
originalExifDict = (__bridge NSMutableDictionary *)(exifDict);
[originalExifDict objectForKey:(NSString *)kCGImagePropertyDPIHeight]
[originalExifDict objectForKey:(NSString *)kCGImagePropertyDPIWidth]
However both the entries in the dictionary come to be 0.
What is the correct way to find the DPI ?
Thanks in advance for the help
CGSize size;
NSNumber *width = (NSNumber *)CFDictionaryGetValue(exifDict, kCGImagePropertyDPIWidth);
NSNumber *height = (NSNumber *)CFDictionaryGetValue(exifDict, kCGImagePropertyDPIHeight);
size.width = [width floatValue];
size.height = [height floatValue];
//Tell me its work or not.
The information isn't in the metadata that comes with your imageDataSampleBuffer. It is written (72 dpi) at the time the image is saved, unless you have, first, manually set it yourself when editing the metadata, before the save.
For most purposes, it is meaningless, However, some software uses it to calculate the "correct size" of an image when placing it in a document. A 3000 pixel square image at 300 dpi will thus appear 10 inches (c.25.4 cm) square; at 72 dpi it will be nearly 42 inches (c.105.8 cm) square. Also, some online image uploaders (especially those used by stock photo libraries and the like) insist on images having high-ish dpi.
If you are using imagePickerController use this below code
NSURL *assetURL = [info objectForKey:UIImagePickerControllerReferenceURL];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library assetForURL:assetURL
resultBlock:^(ALAsset *asset) {
NSMutableDictionary *imageMetadata = nil;
NSDictionary *metadata = asset.defaultRepresentation.metadata;
imageMetadata = [[NSMutableDictionary alloc] initWithDictionary:metadata];
NSLog (#"imageMetaData from AssetLibrary %#",imageMetadata);
NSString *dpi = [imageMetadata objectForKey:#"DPIHeight"];
NSLog (#"Dpi: %#",dpi);
}
failureBlock:^(NSError *error) {
NSLog (#"error %#",error);
}];

ISRC Code from AVMetadataItem objective c

I want to get the ISRC code for Local itunes songs. I can get the metaData by the following codes:
MPMusicPlayerController *mp= mp = [MPMusicPlayerController applicationMusicPlayer];
NSURL *assetURL = [mp.nowPlayingItem valueForProperty:MPMediaItemPropertyAssetURL];
AVAsset *asset = [AVAsset assetWithURL:assetURL];
NSArray *metadata = [asset commonMetadata];
for ( AVMetadataItem* item in metadata ) {
NSString *key = [item commonKey];
NSString *value = [item stringValue];
NSLog(#"extra iptions %#",[item extraAttributes]);
NSLog(#"key = %#, value = %#", key, value);
NSLog(#"keyspace and Local %# %#",[item keySpace],[item key]);
}
But I am really wondering about how to get ISRC(International Standard Record Coding).
Try this (warning: typed into browser)
NSArray *metadata = [asset metadataForFormat:AVMetadataFormatID3Metadata];
if (metadata == nil) {
NSLog(#"No ID3 metadata for asset: %#", asset);
}
// From https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVFoundation_ID3Constants/Reference/reference.html
NSArray *filteredMetadata = [AVMetadataItem metadataItemsFromArray:metadata withKey:AVMetadataID3MetadataKeyInternationalStandardRecordingCode keySpace:nil];
AVMetadataItem *item = [filteredMetadata firstObject];
if (item != nil) {
NSLog(#"ISRC: %#", item.stringValue);
} else {
NSLog(#"No ISRC found for: %#", asset);
}
EDIT: I should mention, the reason your original code didn't print the value of the ISRC is because the ISRC is not part of the common metadata space, and won't be included in the array returned by [asset commonMetadata]. The ISRC key is specific to ID3 metadata, so if your asset does not have ID3 metadata associated with it, you will be unable to retrieve that information.

Objective-C - EXC_BAD_ACCESS error with ALAsset and XmlWriter

I'm using the ALAssetLibrary to retrieve information about the images on the device (IOS Simulator) for the moment.
Now that I have the needed information, I want to write them like an xml file. To do this I'm using the XmlStreamWriter (https://github.com/skjolber/xswi) simple and easy to use. My problem is that I'm having a EXC_BAD_ACCESS (code=1) error when I run the application. I know that it is related to the streamWriter because if I comment this lines of code the program work perfectly.
Here there is my code (I'm using ARC):
XMLWriter* xmlWriter = [[XMLWriter alloc]init];
[xmlWriter writeStartDocumentWithEncodingAndVersion:#"UTF-8" version:#"1.0"];
[xmlWriter writeStartElement:#"Photos"];
NSMutableArray *list = [[NSMutableArray alloc] init];
ALAssetsLibrary* library = [[ALAssetsLibrary alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
if (group) {
[group setAssetsFilter:[ALAssetsFilter allPhotos]];
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop){
if (asset){
[xmlWriter writeStartElement:#"Photos"];
NSString *description = [asset description];
NSRange first = [description rangeOfString:#"URLs:"];
NSRange second = [description rangeOfString:#"?id="];
NSString *path = [description substringWithRange: NSMakeRange(first.location + first.length, second.location - (first.location + first.length))];
[xmlWriter writeAttribute:#"id" value:path];
[xmlWriter writeEndElement:#"Photos"];
}
}];
}
} failureBlock:^(NSError *error) {
NSLog(#"error enumerating AssetLibrary groups %#\n", error);
}];
[xmlWriter writeEndElement];
[xmlWriter writeEndDocument];
NSString* xml = [xmlWriter toString];
NSLog(#"XML: %#", xml);
Any idea of what can be the problem?
I also have an image with the related error:
Thanks
enumerateGroupsWithTypes calls the block to process the found information asynchronously. So, you are calling [xmlWriter writeEndDocument before you have ever actually written any real content into the writer.
You need to change how you complete the write operation so that it is done inside the block and when group is passed as nil. Add an else block to your existing check and put
[xmlWriter writeEndElement];
[xmlWriter writeEndDocument];
NSString* xml = [xmlWriter toString];
NSLog(#"XML: %#", xml);
In it (and whatever you subsequently do).

Extracting latitude and longitude from image Objective c

I'm having a problem while getting the latitude and longitude data from an image(which is having geo location details). I have imported the EXIF framework and I'm using the following code to achieve this:
NSData *jpegData = [UIImageJPEGRepresentation(image, 0.5) base64String];
EXFJpeg* jpegScanner = [[EXFJpeg alloc] init];
[jpegScanner scanImageData: jpegData];
EXFMetaData* exifData = jpegScanner.exifMetaData;
id latitudeValue = [exifData tagValue:[NSNumber numberWithInt:EXIF_GPSLatitude]];
id longitudeValue = [exifData tagValue:[NSNumber numberWithInt:EXIF_GPSLongitude]];
NSLog(#"Longitude: %# Longitude: %#", latitudeValue, longitudeValue);
But its returning the NULL value for both latitude and longitude, can anyone please tell me what I'm doing wrong in the above code? Please help me out. Thanks in Advance!!
You can do it with the alasset framework.
ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc]init];
[assetsLibrary assetForURL:photoUrl resultBlock:resultBlock failureBlock:nil];
ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset *photoAsset) {
CLLocation *location = [photoAsset valueForProperty:ALAssetPropertyLocation];
NSMutableDictionary *exifDataDict = [[NSMutableDictionary alloc] init];
if (location != nil) {
[exifDataDict setObject:[NSNumber numberWithDouble:location.coordinate.latitude] forKey:#"latitude"];
[exifDataDict setObject:[NSNumber numberWithDouble:location.coordinate.longitude] forKey:#"longitude"];
}
}
I had a similar issue once. While dealing with it I got the impression that UIImage sort of strips all or some of the EXIF data. EXIFJpeg worked fine for me when the image data was read from file, boundle or webservice etc. direclty but I did not manage to extract any reasonalbe EXIFs when I stored the image in memory as UIImage object and then used UIImageJPEGRepresentaiion to get the image data and the EXIF from that data.
I will not sign this in blood but that was my impression and using the "raw" data from file did actually work for me. So I received the file from some server, then extracted the EXIF including geo tags (if any) and after that created the UIImage.

Add an NSDictionary to image metadata

I'm trying to save an image with some custom metadata to a Photo Album. The custom metadata I would like to save should be in the form of a NSDictionary. Until now I have only succeeded in inserting an NSArray into the image metadata by using something like below:
NSMutableDictionary *metadata = [[NSMutableDictionary alloc] init];
[metadata setObject:#[#"ele1", #"ele2"] forKey:(NSString*)kCGImagePropertyIPTCKeywords];
NSMutableDictionary *meta = [[NSMutableDictionary alloc] init];
[meta setObject:metadata forKey:(NSString*)kCGImagePropertyIPTCDictionary];
// pass the meta dictionary into writeImageDataToSavedPhotosAlbum
But what I would like is to pass a dictionary into setObject.
Has anyone succeeded in inserting a custom metadata into an image where the metadata is an NSDIctionary?
Additional information
I'm using the code I found here Save CUSTOM metadata in an image taken from AVFoundation in iOS, to add a dictionary to the image metadata but still no luck. The original file is in the temporary directory and the final file is created via writeImageDataToSavedPhotosAlbum. Like in the link, the resulting image doesn't contain the dictionary. Any idea?
CGImageSourceRef source = CGImageSourceCreateWithData((CFMutableDataRef)data, NULL);
NSDictionary *metadata = [(NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source,0,NULL)autorelease];
NSMutableDictionary *metadataAsMutable = [metadata mutableCopy];
NSMutableDictionary *RAWDictionary = [[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyRawDictionary]mutableCopy];
if(!RAWDictionary) {
RAWDictionary = [NSMutableDictionary dictionary];
}
[RAWDictionary setValue:#"value1" forKey:#"key1"];
[RAWDictionary setValue:#"value2" forKey:#"key2"];
[metadataAsMutable setObject:RAWDictionary forKey:(NSString *)kCGImagePropertyRawDictionary];
NSMutableData *newData = [NSMutableData data];
CFStringRef UTI = CGImageSourceGetType(source);
CGImageDestinationRef destination = CGImageDestinationCreateWithData((CFMutableDataRef)newData, UTI, 1, NULL);
if(!destination) {
NSLog(#"***Could not create image destination ***");
}
CGImageDestinationAddImageFromSource(destination,source,0, (CFDictionaryRef)metadataAsMutable);
BOOL success = NO;
success = CGImageDestinationFinalize(destination);
if(!success) {
NSLog(#"***Could not create data from image destination ***");
}
Try this :
//covert image to nsdata format
NSData *imageData = [[NSData alloc]initWithContentsOfFile:#"your image path"];
NSMutableDictionary *metadata = [[NSMutableDictionary alloc] init];
[metadata setObject:imageData forKey:#"imageData"];

Resources