I am using ELCImagePickerController for multiple video selection. But I want to get size of selected video. When user click on any video, then their video size is check.
Right now, all selected video information is getting in:
- (void)elcImagePickerController:(ELCImagePickerController *)picker didFinishPickingMediaWithInfo:(NSArray *)info
{
for (NSDictionary *dict in info) {
NSUrl *video url = [dict objectForKey:UIImagePickerControllerReferenceURL];
NSLog(#"Video information is ::",url);
}
}
I can find the video size in didFinishPickingMediaWithInfo: method . But this method is called when user select all video. But I want to restrict user from selection of large size file.
I want to get video information when a user click on video ,If user click on one video then that video size is get and show a alert related to large size .
Following is called when user tap on a video for selecting. But I am unable to get video information at this time .
ELCImagePickerController.m
- (BOOL)shouldSelectAsset:(ELCAsset *)asset previousCount:(NSUInteger)previousCount
{
BOOL shouldSelect = previousCount < self.maximumImagesCount;
if (!shouldSelect) {
NSString *title = [NSString stringWithFormat:NSLocalizedString(#"Only %d Video please!", nil), self.maximumImagesCount];
NSString *message = [NSString stringWithFormat:NSLocalizedString(#"You can only upload %d Videos at a time.", nil), self.maximumImagesCount];
[[[UIAlertView alloc] initWithTitle:title
message:message
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:NSLocalizedString(#"Okay", nil), nil] show];
}
return shouldSelect;
}
Check the below code Length:`
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:yourVideoUrl];
CMTime duration = playerItem.duration;
float seconds = CMTimeGetSeconds(duration);
NSLog(#"duration: %.2f", seconds);`
Check the below code Size:
There are 1024 bytes in a kilobyte and 1024 kilobytes in a megabyte
NSData * movieData = [NSData dataWithContentsOfURL:yourVideoUrl];
NSLog(#"%.2f",(float)movieData.length/1024.0f/1024.0f);
Related
In my app I have to implement save image feature. I have managed saving like this:
UIImage *image = [UIImage imageNamed:actualBackground];
UIImageWriteToSavedPhotosAlbum(
image, self,
#selector(thisImage:hasBeenSavedInPhotoAlbumWithError:usingContextInfo:),
nil);
/* ... */
- (void)thisImage:(UIImage *)image
hasBeenSavedInPhotoAlbumWithError:(NSError *)error
usingContextInfo:(void *)ctxInfo {
if (!error){
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
[self presentViewController:picker animated:YES completion:nil];
}
}
Unfortunately I have to check if file already exists to prevent redundant saving. Also this is necessary because saving multiple times the same image don't override one file, but it creates copy of it...
Do you know how to solve that problem?
SOLUTION:
According to Shravya Boggarapu answer I'm storing assetUrl in my NSUserDefaults. Complete code:
- (IBAction)onDownloadClick:(UIButton *)sender {
UIImage *image = [UIImage imageNamed:actualBackground];
NSString *key = [NSString stringWithFormat:#"assetsUrl %#", actualBackground];
NSString *savedValue =
[[NSUserDefaults standardUserDefaults] stringForKey:key];
NSURL *url = [NSURL URLWithString:savedValue];
if (url != nil) {
PHFetchResult *fetch =
[PHAsset fetchAssetsWithALAssetURLs:[NSArray arrayWithObject:url]
options:nil];
if ([fetch count]) {
UIAlertView *myAlert = [[UIAlertView alloc]
initWithTitle:nil
message:NSLocalizedString(#"Already downloaded", nil)
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[myAlert show];
return;
}
}
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library
writeImageToSavedPhotosAlbum:image.CGImage
orientation:(ALAssetOrientation)image.imageOrientation
completionBlock:^(NSURL *assetURL, NSError *error) {
[library assetForURL:assetURL
resultBlock:^(ALAsset *asset) {
NSLog(#"assetURL %#", assetURL);
NSString *ass = [assetURL absoluteString];
[[NSUserDefaults standardUserDefaults]
setObject:ass
forKey:key];
[[NSUserDefaults standardUserDefaults] synchronize];
UIAlertView *myAlert = [[UIAlertView alloc]
initWithTitle:nil
message:NSLocalizedString(
#"Image downloaded", nil)
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[myAlert show];
}
failureBlock:^(NSError *error){
}];
}];
}
Hope it will help somebody.
I have a solution but not one that applies to every situation.
The thing about saving image to camera roll is that there is an assetURL created when you add the image to camera roll. Also, this asset URL is new every time, so if you save to camera roll, it will create a copy. The name of the image is also not retained.
If the image is added to the camera roll through your app in the first place, then you can store the assetURL as part of image information.
In my app, a dictionary is maintained for every image containing some critical info. This includes the assetURL of the image if it is saved to camera roll.
Once you have the URL, you can check its existence by using fetchAssetsWithALAssetURLs:options: function.
If the URL is nil or the asset when fetched is nil, it means that the image does not exist in the camera roll. So you can add anew.
There is no easy way to compare two images and if you found one that will surly a heavy task, instead of this we can compare image's meta data which we can write it to image and also read it from images.
You can use this repo for that
And ALAssetLibrary also have some properties to access an images meta info. If you google with this you will surly get some.
Like this one
I am working on adding video to a chat application. The users can either share a video chosen from their files or record a new one to upload.
The issue I am having is differentiating between a video which has just been recorded and a video which has been selected as I want to save a just recorded video to their album when they upload it.
Currently my code looks like this:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
// This checks whether we are adding image or video (public.movie for video)
if ([[info objectForKey:UIImagePickerControllerMediaType] isEqualToString:#"public.image"]) {
UIImage * image = [info objectForKey:UIImagePickerControllerEditedImage];
[self sendImage:image];
}
else {
// SS-V
// If we are dealing with a video then we want to return to the chat view and post the video
NSURL * videoURL = (NSURL *)[info objectForKey:UIImagePickerControllerMediaURL];
// Send video to the chat view
[self sendVideo:[videoURL absoluteString]];
}
[tableView reloadData];
[picker dismissViewControllerAnimated:YES completion:Nil];
}
So I am getting the local url of the video and then uploading it to an external database.
I have also got this code:
// Save the recorded video to the iPhone
NSString * videoCompatibleString = [videoURL.absoluteString stringByReplacingOccurrencesOfString:#"file://" withString:#""];
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(videoCompatibleString)) {
UISaveVideoAtPathToSavedPhotosAlbum (videoCompatibleString, self, nil, nil);
}
Which will save it to my phone library.
So now my only issue is how to differentiate between a video just taken and a video selected from my library already.
I was hoping there would be an elegant way of achieving this. Seemingly there isn't and so I set up an enum to record what I loaded the image picker with, if I loaded it with the camera then I knew that I would be taking the video or picture so should add it to the album:
In the header file:
typedef enum {
bPictureTypeCamera,
bPictureTypeAlbumImage,
bPictureTypeAlbumVideo,
} bPictureType;
// This allows us to see what kind of media is being sent to know if we need to save it to album
bPictureType _pictureType;
In the main file:
// If we have just taken the media then save it to the users camera
if (_pictureType == bPictureTypeCamera) {
[self saveMediaWithInfo:info];
}
With my save function checking if it is video or image and saving it:
- (void)saveMediaWithInfo: (NSDictionary *)info {
// Save image
if ([[info objectForKey:UIImagePickerControllerMediaType] isEqualToString:#"public.image"]) {
UIImageWriteToSavedPhotosAlbum([info objectForKey:UIImagePickerControllerEditedImage], self, nil, nil);
}
// Save Video
else {
// Make sure the video is in a compatible format to save
NSURL * videoURL = (NSURL *)[info objectForKey:UIImagePickerControllerMediaURL];
NSString * videoCompatibleString = [[videoURL absoluteString] stringByReplacingOccurrencesOfString:#"file://" withString:#""];
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum (videoCompatibleString)) {
UISaveVideoAtPathToSavedPhotosAlbum (videoCompatibleString, self, nil, nil);
}
}
}
Now the neatest answer but it does what it needs to
I want to create custom photo album and save photo to specific album in iOS 7. and I found iOS save photo in an app specific album using ALAssetsLibrary.
But I don't know how to do it using UIActivityViewController.
NSArray* actItems = [NSArray arrayWithObjects: image, nil];
UIActivityViewController *activityView = [[UIActivityViewController alloc]
initWithActivityItems:actItems
applicationActivities:nil];
[activityView setCompletionHandler:^(NSString *activityType, BOOL completed)
{
if ([activityType isEqualToString:UIActivityTypeSaveToCameraRoll])
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"#Saved_title", nil)
message:NSLocalizedString(#"#Saved_message2", nil)
delegate:self
cancelButtonTitle:NSLocalizedString(#"OK", nil)
otherButtonTitles: nil];
[alert show];
}
}];
I realize the question is a few months old and that the OP may have moved on, but I needed to do exactly this, but didn't find another solution, and needed to come up with my own.
It's not fool-proof, as if there are multiple copies of the video/image in Camera Roll that you're wanting to copy, it will copy all of them, which may or may not be desired. Also, for my purposes, I'm considering maintaining a persistent list of asset URLs that I've written to the custom album so that I skip that asset in the future, but I haven't yet coded it because, if the user removes the video/image from the custom album, it'd be nearly impossible to update that list without more iteration through asset groups: something I'd like to avoid.
Last disclaimer: I haven't tested this a whole ton yet, but it works for my purposes, so hopefully someone else out there can benefit from it.
I augmented Marin Todorov's ALAssetsLibrary+CustomPhotoAlbum category, which I found here: https://github.com/yusenhan/Smooth-Line-View/tree/master/ALAssetsLibrary%2BCustomPhotoAlbum. Note: there is no license information provided there, so I'm assuming that modifying the source for this category is ok.
Here is my method which sets up and displays the UIActivityViewController:
- (void)showActivitySheet:(NSString *)path {
NSURL *newURL = [NSURL fileURLWithPath:path];
NSArray *itemsToShare = #[newURL];
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:itemsToShare applicationActivities:nil];
activityVC.excludedActivityTypes = #[UIActivityTypePrint, UIActivityTypeAssignToContact, UIActivityTypeAddToReadingList];
// Once the OS has finished with whatever the user wants to do with it,
// we'll begin figuring out if we need to save it to the Album, too!
[activityVC setCompletionHandler:^(NSString *activityType, BOOL completed) {
// If the user selected "Save to Camera Roll"
if ([activityType isEqualToString:UIActivityTypeSaveToCameraRoll]) {
ALAssetsLibrary *lib = [[ALAssetsLibrary alloc] init];
NSURL *tempUrl = [NSURL fileURLWithPath:path];
// saveMovie: below is a method I added to the category, but you can use saveImage:,
// which you'll also likely want to add some kind of parameter to so, in the category,
// you know when you only want to copy to the Album instead of the Album AND Camera Roll
[lib saveMovie:tempUrl toAlbum:#"CUSTOM ALBUM NAME"
withCompletionBlock:^(NSURL *url, NSError *error) {
if (error) {
NSLog(#"Error writing movie to custom album: %#", error.debugDescription);
}
}
onlyWriteToCustomAlbum:YES];
}
}];
[self presentViewController:activityVC animated:YES completion:nil];
}
Here is code you can add to the saveImage: method in the ALAssetsLibrary+CustomPhotoAlbum category so you can save it to your custom Album, too! You could execute this portion only on the YES case of the BOOL which you'll want to add to the category.
NSData *dataToCompareTo = [NSData dataWithContentsOfURL:url]; // This data represents the image/movie which you want to save into the custom album. The one you handed to the UIActivityViewController.
// Note use of self, as this is a category on ALAssetsLibrary; also, this
// assumes that you've already written the photo to the Camera Roll, which
// should be automatically handled by the OS, if the user hit the "Save" button
// on the UIActivityViewController.
// Enumerate through Camera Roll/Saved Photos group.
[self enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
// Enumerate the assets in each group.
[group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
ALAssetRepresentation *rep = [result defaultRepresentation];
// If the asset isn't the same size as the source image/movie
// it shouldn't be the same. Check the size first, since it
// is a less costly operation than byte checking the data itself.
if ([rep size] == [dataToCompareTo length]) {
Byte *buffer = malloc([NSNumber numberWithLongLong:rep.size].unsignedLongValue);
NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:[NSNumber numberWithLongLong:rep.size].unsignedLongValue error:nil];
NSData *data = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];
// If the buffer has more than the null-termination char, free it! I'm doing this in case the above call to dataWithBytesNoCopy fails to free() the buffer.
if (sizeof(buffer) > 4) {
free(buffer);
}
// Ensure they are the same by comparing the NSData instances.
if ([data isEqualToData:dataToCompareTo]) {
NSLog(#"they are the same!!");
[self addAssetURL:[rep url]
toAlbum:albumName
withMovieCompletionBlock:completionBlock];
} else {
NSLog(#"they are different");
}
}
}];
} failureBlock:^(NSError *error) {
NSLog(#"Failed to write to custom album!");
}];
Hope it helps! TLDR? Thought so! ;-)
i've been using an html string for a long period for playing youtube videos through an UIWebView, the problem is i want to get notifications with playbackstate changed. i've decided to create an MPMoviePlayerController and play the youtube video through this, but cant seem to make it work. i'm using following code in viewdidload:
NSString *urlAddress = #"http://www.youtube.com/watch?v=m01MYOpbdIk";
NSURL *url = [NSURL URLWithString:urlAddress];
CGFloat width = [UIScreen mainScreen].bounds.size.width;
CGFloat height = [UIScreen mainScreen].bounds.size.height;
movie = [[MPMoviePlayerController alloc] initWithContentURL:url];
movie.scalingMode=MPMovieScalingModeAspectFill;
movie.view.frame = CGRectMake(0.0, 0.0, width, height);
[self.view addSubview:movie.view];
[movie play];
Gives me this error:
_itemFailedToPlayToEnd: {
kind = 1;
new = 2;
old = 0;
}
For me this library did work perfectly! https://github.com/hellozimi/HCYoutubeParser
moviePlayer = [[MPMoviePlayerController alloc] init];
moviePlayer.shouldAutoplay = YES;
moviePlayer.fullscreen = YES;
moviePlayer.repeatMode = MPMovieRepeatModeNone;
moviePlayer.controlStyle = MPMovieControlStyleDefault;
moviePlayer.movieSourceType = MPMovieSourceTypeFile;
moviePlayer.scalingMode = MPMovieScalingModeAspectFit;
After this call method.
[self callYouTubeURL:[NSString stringWithFormat:#"http://www.youtube.com/embed/%#",_urlcode]];
In this method parse youtube link.
- (void)callYouTubeURL:(NSString *)urlLink
{
NSURL *url = [NSURL URLWithString:urlLink];
actvity.hidden = NO;
[HCYoutubeParser thumbnailForYoutubeURL:url thumbnailSize:YouTubeThumbnailDefaultHighQuality completeBlock:^(UIImage *image, NSError *error) {
if (!error) {
[HCYoutubeParser h264videosWithYoutubeURL:url completeBlock:^(NSDictionary *videoDictionary, NSError *error) {
NSDictionary *qualities = videoDictionary;
NSString *URLString = nil;
if ([qualities objectForKey:#"small"] != nil) {
URLString = [qualities objectForKey:#"small"];
}
else if ([qualities objectForKey:#"live"] != nil) {
URLString = [qualities objectForKey:#"live"];
}
else {
[[[UIAlertView alloc] initWithTitle:#"Error" message:#"Couldn't find youtube video" delegate:nil cancelButtonTitle:#"Close" otherButtonTitles: nil] show];
return;
}
_urlToLoad = [NSURL URLWithString:URLString];
[self urlLoadintoPlayer];
}];
}
else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:[error localizedDescription] delegate:nil cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
[alert show];
}
}];
}
After this load newly parse url into player.
-(void)urlLoadintoPlayer
{
moviePlayer.contentURL = _urlToLoad;
}
Make use of custom LBYouTubePlayerViewController
It is a subclass of MPMoviePlayerViewController.
LBYouTubeView is just a small view that is able to display YouTube videos in a MPMoviePlayerController. You even have the choice between high-quality and standard quality stream.
It just loads the HTML code of YouTube's mobile website and looks for the data in the script tag.
LBYouTubeView doesn't use UIWebView which makes it faster and look cleaner.
Official way to play youtube videos: 1) UIWebView with the embed tag from Youtube the UIWebView's content.2) Using youtube-ios-player-helper[Google official way]
Unfortunately, there's no way to directly play a youtube video with MPMoviePlayerController because youtube does not expose direct links to the video files.
There are library which runs youtube videos through MPMoviePlayerController, but they are against the TOC of youtube. Hence simplest method is to go for youtube-ios-player-helper.
In case youtube-ios-player-helper pod doesn't work you can add YTPlayer.h/.m and assets folder to your project and write a bridge header with #import "YTPlayerView.h" and rest procedure you can follow on https://github.com/youtube/youtube-ios-player-helper
This definitely worked for me!
I'm building an iOS app that allows the user to upload videos from UIImagePickerController, either by recording or choosing them from the Camera Roll, as well as also play the chosen video. My question is, how would I go about keeping a reference to the videos that have been chosen this way? I want to do this so that if the video is still present on the device, I can use the local file rather than streaming the uploaded file.
When
imagePickerController:didFinishPickingMediaWithInfo:
returns, the URL in:
[info objectForKey:UIImagePickerControllerMediaURL];
Is in the format of: "file://localhost/private/var/mobile/Applications/ /tmp//trim.z2vLjx.MOV"
I'm lead to believe that the "/tmp/" directory is temporary, and therefore not suitable to save the URL for that location.
I can get all of the videos on the device through ALAssetsLibrary, but because I don't have a way of distinguishing them, this doesn't help me. I've been attempting to use:
[result valueForProperty:ALAssetPropertyDate];
To distinguish the videos, but I need a way of getting the creation date from UIImagePickerController for this to be useful.
I've finally managed to find a solution:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if(CFStringCompare((CFStringRef) mediaType, kUTTypeMovie, 0) == kCFCompareEqualTo)
{
//Dismiss the media picker view
[picker dismissModalViewControllerAnimated:YES];
//Get the URL of the chosen content, then get the data from that URL
NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
NSData *webData = [NSData dataWithContentsOfURL:videoURL];
//Gets the path for the URL, to allow it to be saved to the camera roll
NSString *moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] path];
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum (moviePath))
{
ALAssetsLibrary *lib = [[ALAssetsLibrary alloc] init];
//The key UIImagePickerControllerReferenceURL allows you to get an ALAsset, which then allows you to get metadata (such as the date the media was created)
[lib assetForURL:[info objectForKey:UIImagePickerControllerReferenceURL] resultBlock:^(ALAsset *asset) {
NSLog(#"created: %#", [asset valueForProperty:ALAssetPropertyDate]);
} failureBlock:^(NSError *error) {
NSLog(#"error: %#", error);
}];
}
}
As per usual, the solution was found by reading the documentation a little more thoroughly. Hopefully this'll help someone else out at some point.
You can easily keep a record of the videos you have on the device. Either by keeping a data base (which I think would be too much) or just a file with a list of your videos. In that list, you could have the URL of the assets.