AVAssetExportSession progress gets stuck on ipad but not on simulator - ios

This piece of code works fine on the simulator. However, when I try to run the export on my iPad, it always hangs at progress value 0.14583-ish. Can somebody help me figure out why? been stuck on this for quite awhile.
Here is my code:
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:composition];
if ([compatiblePresets containsObject:AVAssetExportPresetLowQuality]) {
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]
initWithAsset:composition presetName:AVAssetExportPresetLowQuality];
exportSession.outputURL = [NSURL fileURLWithPath:[[ShowDAO getUserDocumentDir] stringByAppendingString:exportFilename]];
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
CMTime start = CMTimeMakeWithSeconds(0, 1);
CMTime duration = CMTimeMakeWithSeconds(1000, 1);
CMTimeRange range = CMTimeRangeMake(start, duration);
exportSession.timeRange = range;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch ([exportSession status]) {
case AVAssetExportSessionStatusCompleted:
NSLog(#"Export Completed");
break;
case AVAssetExportSessionStatusFailed:
NSLog(#"Export failed: %#", [[exportSession error] localizedDescription]);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(#"Export cancelled");
break;
default:
break;
}
}];
while(exportSession.progress != 1.0){
NSLog(#"loading... : %f",exportSession.progress);
sleep(1);
}
[exportSession release];
}

while(exportSession.progress != 1.0){
NSLog(#"loading... : %f",exportSession.progress);
sleep(1);
}
This while loop is blocking the main thread. The NSLog might not be able to fire properly. Try it without the while loop?

Related

How to send large file as chunks via MCSession NSOutputStream

I want to send large video file to connected peer in chunks via NSOutputStream
I am using below code.
NSError *error;
self.outputStream = [_appDelegate.mcManager.session startStreamWithName:#"Mystream" toPeer:[[_appDelegate.mcManager.session connectedPeers] objectAtIndex:0] error:&error];
At receiver side NSStream delegate not receiving entire send data.
-(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{
switch(eventCode) {
case NSStreamEventEndEncountered:
break;
case NSStreamEventHasBytesAvailable:
if ([aStream isKindOfClass:[NSInputStream class]]) {
}
break;
case NSStreamEventErrorOccurred:
break;
case NSStreamEventHasSpaceAvailable:
break;
case NSStreamEventNone:
break;
case NSStreamEventOpenCompleted:
break;
}
}

How to play videos from stream URL with some pre-buffering mechanism the way facebook did?

In my app I have Timeline like facebook and want to implement autoplay the way facebook does. I am able to play a video whenever user stops scrolling on Video post inside UITableViewCell but it takes 5-10 seconds to play a video thats the problem.
I need expert guide how to pre - buffer videos from urls at-least 5 sec to give a user better experience or what is other way to play videos from URL instantly on 3g network. A user might have 100 videos post.
I can't find out which class buffers the videos AVURLAsset , AVPlayerItem or AVPlayer while playing .
I am loading AVURLAsset loadValuesAsynchronouslyForKeys and creating AVPlayerItems then Saving to NSDictionary for URL Key.
Below is my code. For security reasons URL gets expired after 15 minutes.
-(void)setContentURL:(NSURL *)contentURL
{
if (contentURL)
{
[self.moviePlayer replaceCurrentItemWithPlayerItem:nil];
[_activityIndicator startAnimating];
__block AVPlayerItem *playerItem=[_appDelegate.dictAVPlayerItems objectForKey:[contentURL.absoluteString stringByAppendingString:self.postIdOrBlogId]];
if (!playerItem)
{
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:contentURL options:nil];
NSArray *keys = [NSArray arrayWithObject:#"playable"];
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^()
{
NSLog(#"keys %#", keys);
[self checkAssestStatus:asset];
if (asset==nil)return ;
playerItem = [AVPlayerItem playerItemWithAsset:asset];
[_appDelegate.dictAVPlayerItems setObject:playerItem forKey:[contentURL.absoluteString stringByAppendingString:self.postIdOrBlogId]];
dispatch_async(dispatch_get_main_queue(),
^{
[self addPlayerItem:playerItem isNewAsset:NO];
});
}];
_contentURL = contentURL;
}
else
[self addPlayerItem:playerItem isNewAsset:YES];
}
}
-(void)checkAssestStatus:(AVURLAsset*)asset
{
NSError *error = nil;
AVKeyValueStatus tracksStatus = [asset statusOfValueForKey:#"playable" error:&error];
NSLog(#" AVURLAsset error = %#",error);
if(!asset.isPlayable)
{
NSLog(#"assest is not playable");
[self.activityIndicator stopAnimating];
return;
}
switch (tracksStatus) {
case AVKeyValueStatusLoaded:
{
NSLog(#"loaded");
}
break;
case AVKeyValueStatusFailed:
{
if (error && (error.code == AVErrorUnknown
|| error.code == AVErrorFailedToLoadMediaData))
{
[_appDelegate.dictAVPlayerItems removeObjectForKey:[asset.URL.absoluteString stringByAppendingString:self.postIdOrBlogId]];
NSLog(#"url Expired");
asset=nil;
[CommonTimelineAPI requestFreshURLFor:asset.URL.absoluteString withCompletionBlock:^(NSString *freshURL, NSError *error) {
if(freshURL)
{
NSURL* url=[NSURL URLWithString:freshURL];
if (url)
{
self.contentURL=url;
}
}
}];
}
}
break;
case AVKeyValueStatusCancelled:
{
NSLog(#"cancelled");
}
break;
case AVKeyValueStatusUnknown:
{
NSLog(#"unkonwn");
}
break;
case AVKeyValueStatusLoading:
{
NSLog(#"Loading");
}break;
}
}

NSStream delegate method stream:handleEvent: crashing application with EXC_BAD_ACCESS code=1

I am using NSInputStream to upload media file to server in following way.
uploadInputStream = [[NSInputStream alloc] initWithFileAtPath:videoFilePath];
uploadInputStream.delegate = self;
[uploadInputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[uploadInputStream open];
And in NSStream delegate method stream:handleEvent: i am fetching chunk of media file and uploading to server.
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
switch (eventCode) {
case NSStreamEventOpenCompleted:
NSLog(#"Strem opened");
break;
case NSStreamEventHasBytesAvailable: {
uint8_t buf[1024*1024];
unsigned int len = 0;
len = [(NSInputStream *)aStream read:buf maxLength:1024*1024];
if(len)
{
#autoreleasepool {
NSMutableData *fileData = [NSMutableData data];
[fileData appendBytes:(const void *)buf length:len];
[self uploadVideo:fileData];
}
}
break;
}
case NSStreamEventHasSpaceAvailable:
break;
case NSStreamEventEndEncountered: {
break;
}
case NSStreamEventErrorOccurred:
break;
case NSStreamEventNone:
break;
default:
break;
}
}
So far so good and everything works fine in simulator. The issue is if i test this same code in real device (iPad-mini for now), it always crashing the application with EXC_BAD_ACCESS code=1 at strating of the delegate method stream:handleEvent: .
Anyone has any idea about this? Any help will be appreciated.
Thanks,
Jay Stepin.

AVAssetExportSession send cancel export

I am making a video app where I create a new video using AVAssetExportSession. While the video is being created I want to give the user ability to cancel video creation. The problem I have is that I do not know how can I send a cancellation request to AVAssetExportSession as I assume it's running on the main thread. Once it starts I have no idea how can I send a stop request?
I tried this but it doesn't work
- (IBAction) startBtn
{
....
// Export
exportSession = [[AVAssetExportSession alloc] initWithAsset:[composition copy] presetName:AVAssetExportPresetHighestQuality];
[exportSession setOutputFileType:#"com.apple.quicktime-movie"];
exportSession.outputURL = outputMovieURL;
exportSession.videoComposition = mainComposition;
//NSLog(#"Went Here 7 ...");
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch ([exportSession status])
{
case AVAssetExportSessionStatusCancelled:
NSLog(#"Canceled ...");
break;
case AVAssetExportSessionStatusCompleted:
{
NSLog(#"Complete ... %#",outputURL); // moview url
break;
}
case AVAssetExportSessionStatusFailed:
{
NSLog(#"Faild=%# ...",exportSession.error);
break;
}
case AVAssetExportSessionStatusExporting:
NSLog(#"Exporting.....");
break;
}
}];
}
- (IBAction) cancelBtn
{
exportSession = nil;
}
You can cancel an export session by sending it the message cancelExport.
To accomplish this, you simply need to have an ivar (or property) which holds the current active export session:
#property (nonatomic, strong) AVAssetExportSession* exportSession;
Initialize the property:
- (IBAction) startBtn {
if (self.exportSession == nil) {
self.exportSession = [[AVAssetExportSession alloc] initWithAsset:[composition copy]
presetName:AVAssetExportPresetHighestQuality];
...
[self.exportSession exportAsynchronouslyWithCompletionHandler:^{
self.exportSession = nil;
....
}];
}
else {
// there is an export session already
}
}
In order to cancel the session:
- (IBAction) cancelBtn
{
[self.exportSession cancelExport];
self.exportSession = nil;
}
Hint: For a better user experience, you should disable/enable "Cancel" and "Start Export" buttons accordingly.

AVAssetExportSession SLOW

I am using AVAssetExportSession to export audio files. It is working, though in a speed that is practical for use. I am setting up my exporter, getting my AVAsset, and starting the export. Here is the code. Any suggestions or insight will help.
[exporter exportAsynchronouslyWithCompletionHandler:^{
NSLog(#"we are now exporting");
int exportStatus = exporter.status;
switch (exportStatus) {
case AVAssetExportSessionStatusFailed: {
// log error to text view
NSError *exportError = exporter.error;
NSLog (#"AVAssetExportSessionStatusFailed: %#", exportError);
break;
}
case AVAssetExportSessionStatusCompleted: {
NSLog (#"AVAssetExportSessionStatusCompleted");
// set up AVPlayer
NSData *data = [NSData dataWithContentsOfURL:exportURL];
break;
}
case AVAssetExportSessionStatusUnknown: { NSLog (#"AVAssetExportSessionStatusUnknown"); break;}
case AVAssetExportSessionStatusExporting: { NSLog (#"AVAssetExportSessionStatusExporting"); break;}
case AVAssetExportSessionStatusCancelled: { NSLog (#"AVAssetExportSessionStatusCancelled"); break;}
case AVAssetExportSessionStatusWaiting: { NSLog (#"AVAssetExportSessionStatusWaiting"); break;}
default: { NSLog (#"didn't get export status"); break;}
}
[exporter release];
[exportURL release];
}];
You're probably causing some kind of conversion - that will be slow (not that much faster than realtime). Make sure you're using the passthrough preset, AVAssetExportPresetPassthrough.

Resources