- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我必须将大文件大小的歌曲从 iTunes 库转换为较小的 8K 歌曲文件。
正如我执行异步转换一样,即使未完成写入 doc 文件夹,bool 始终返回 true。目前,我在再次调用该函数之前使用了 10 秒的延迟,它在 iPhone 5s 的过渡期间运行良好,但我想适应速度较慢的设备。
请给我一些关于我的代码的指示/建议。
-(void)startUploadSongAnalysis
{
[self updateProgressYForID3NForUpload:NO];
if ([self.uploadWorkingAray count]>=1)
{
Song *songVar = [self.uploadWorkingAray objectAtIndex:0];//core data var
NSLog(@"songVar %@",songVar.songName);
NSLog(@"songVar %@",songVar.songURL);
NSURL *songU = [NSURL URLWithString:songVar.songURL]; //URL of iTunes Lib
// self.asset = [AVAsset assetWithURL:songU];
// NSLog(@"asset %@",self.asset);
NSError *error;
NSString *subString = [[songVar.songURL componentsSeparatedByString:@"id="] lastObject];
NSString *savedPath = [self.documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:@"audio%@.m4a",subString]];//save file name of converted 8kb song
NSString *subStringPath = [NSString stringWithFormat:@"audio%@.m4a",subString];
if ([self.fileManager fileExistsAtPath:savedPath] == YES)
[self.fileManager removeItemAtPath:savedPath error:&error];
NSLog(@"cacheDir %@",savedPath);
//export low bitrate song to cache
if ([self exportAudio:[AVAsset assetWithURL:songU] toFilePath:savedPath]) // HERE IS THE PROBLEM, this return true even the writing is not completed cos when i upload to my web server, it will say song file corrupted
{
// [self performSelector:@selector(sendSongForUpload:) withObject:subStringPath afterDelay:1];
[self sendRequest:2 andPath:subStringPath andSongDBItem:songVar];
}
else
{
NSLog(@"song too short, skipped");
[self.uploadWorkingAray removeObjectAtIndex:0];
[self.songNotFoundArray addObject:songVar];
[self startUploadSongAnalysis];
}
}
else //uploadWorkingAray empty
{
NSLog(@"save changes");
[[VPPCoreData sharedInstance] saveAllChanges];
}
}
#pragma mark song exporter to doc folder
- (BOOL)exportAudio:(AVAsset *)avAsset toFilePath:(NSString *)filePath
{
CMTime assetTime = [avAsset duration];
Float64 duration = CMTimeGetSeconds(assetTime);
if (duration < 40.0) return NO; // if song too short return no
// get the first audio track
NSArray *tracks = [avAsset tracksWithMediaType:AVMediaTypeAudio];
if ([tracks count] == 0) return NO;
NSError *readerError = nil;
AVAssetReader *reader = [[AVAssetReader alloc] initWithAsset:avAsset error:&readerError];
//AVAssetReader *reader = [AVAssetReader assetReaderWithAsset:avAsset error:&readerError]; // both works the same ?
AVAssetReaderOutput *readerOutput = [AVAssetReaderAudioMixOutput
assetReaderAudioMixOutputWithAudioTracks:avAsset.tracks
audioSettings: nil];
if (! [reader canAddOutput: readerOutput])
{
NSLog (@"can't add reader output...!");
return NO;
}
else
{
[reader addOutput:readerOutput];
}
// writer AVFileTypeCoreAudioFormat AVFileTypeAppleM4A
NSError *writerError = nil;
AVAssetWriter *writer = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:filePath]
fileType:AVFileTypeAppleM4A
error:&writerError];
//NSLog(@"writer %@",writer);
AudioChannelLayout channelLayout;
memset(&channelLayout, 0, sizeof(AudioChannelLayout));
channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
// use different values to affect the downsampling/compression
// NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
// [NSNumber numberWithInt: kAudioFormatMPEG4AAC], AVFormatIDKey,
// [NSNumber numberWithFloat:16000.0], AVSampleRateKey,
// [NSNumber numberWithInt:2], AVNumberOfChannelsKey,
// [NSNumber numberWithInt:128000], AVEncoderBitRateKey,
// [NSData dataWithBytes:&channelLayout length:sizeof(AudioChannelLayout)], AVChannelLayoutKey,
// nil];
NSDictionary *outputSettings = @{AVFormatIDKey: @(kAudioFormatMPEG4AAC),
AVEncoderBitRateKey: @(8000),
AVNumberOfChannelsKey: @(1),
AVSampleRateKey: @(8000)};
AVAssetWriterInput *writerInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeAudio outputSettings:outputSettings];
//\Add inputs to Write
NSParameterAssert(writerInput);
NSAssert([writer canAddInput:writerInput], @"Cannot write to this type of audio input" );
if ([writer canAddInput:writerInput])
{
[writer addInput:writerInput];
}
else
{
NSLog (@"can't add asset writer input... die!");
return NO;
}
[writerInput setExpectsMediaDataInRealTime:NO];
[writer startWriting];
[writer startSessionAtSourceTime:kCMTimeZero];
[reader startReading];
__block UInt64 convertedByteCount = 0;
__block BOOL returnValue;
__block CMSampleBufferRef nextBuffer;
dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL);
[writerInput requestMediaDataWhenReadyOnQueue:mediaInputQueue usingBlock:^{
// NSLog(@"Asset Writer ready : %d", writerInput.readyForMoreMediaData);
while (writerInput.readyForMoreMediaData)
{
nextBuffer = [readerOutput copyNextSampleBuffer];
if (nextBuffer)
{
[writerInput appendSampleBuffer: nextBuffer];
convertedByteCount += CMSampleBufferGetTotalSampleSize (nextBuffer);
//NSNumber *convertedByteCountNumber = [NSNumber numberWithLong:convertedByteCount];
//NSLog (@"writing");
CFRelease(nextBuffer);
}
else
{
[writerInput markAsFinished];
[writer finishWritingWithCompletionHandler:^{
if (AVAssetWriterStatusCompleted == writer.status)
{
NSLog(@"Writer completed");
returnValue = YES; //I NEED TO RETURN SOMETHING FROM HERE AFTER WRITING COMPLETED
dispatch_async(mediaInputQueue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
// add this to the main queue as the last item in my serial queue
// when I get to this point I know everything in my queue has been run
NSDictionary *outputFileAttributes = [[NSFileManager defaultManager]
attributesOfItemAtPath:filePath
error:nil];
NSLog (@"done. file size is %lld",
[outputFileAttributes fileSize]);
});
});
}
else if (AVAssetWriterStatusFailed == writer.status)
{
[writer cancelWriting];
[reader cancelReading];
NSLog(@"Writer failed");
return;
}
else
{
NSLog(@"Export Session Status: %d", writer.status);
}
}];
break;
}
}
}];
tracks = nil;
writer = nil;
writerInput = nil;
reader = nil;
readerOutput=nil;
mediaInputQueue = nil;
return returnValue;
//return YES;
}
最佳答案
您的方法 exportAudio:toFilePath:
实际上是一个异步 方法,需要一些修复才能成为一个合适的异步方法。
首先,您应该提供一个完成处理程序,以便向调用站点发出底层任务已完成的信号:
- (void)exportAudio:(AVAsset *)avAsset
toFilePath:(NSString *)filePath
completion:(completion_t)completionHandler;
请注意,该方法的结果是通过完成处理程序传递的,其签名可能如下所示:
typedef void (^completion_t)(id result);
其中参数result 是方法的最终结果。当在方法中设置各种对象时,当任何出错时,您应该总是返回一个NSError
对象——即使,该方法可能返回一个立即结果指示错误。
接下来,如果您查看文档,您可以阅读:
- (void)requestMediaDataWhenReadyOnQueue:(dispatch_queue_t)queue
usingBlock:(void (^)(void))block
Discussion
The block should append media data to the input either until the input’s readyForMoreMediaData property becomes NO or until there is no more media data to supply (at which point it may choose to mark the input as finished using markAsFinished). The block should then exit. After the block exits, if the input has not been marked as finished, once the input has processed the media data it has received and becomes ready for more media data again, it will invoke the block again in order to obtain more.
您现在应该非常确定您的任务真正完成了。您在 传递给方法 requestMediaDataWhenReadyOnQueue:usingBlock:
的 block 中确定这一点。
当任务完成时,您调用中提供的完成处理程序completionHandler方法 exportAudio:toFilePath:completion:
。
当然,您需要修复您的实现,例如方法以
结尾 tracks = nil;
writer = nil;
writerInput = nil;
reader = nil;
readerOutput=nil;
mediaInputQueue = nil;
return returnValue;
//return YES;
}
当然没有意义。清理并返回结果应在异步任务实际完成时完成。除非在设置期间发生错误,否则您需要在传递给方法 requestMediaDataWhenReadyOnQueue:usingBlock:
的 block 中确定这一点。
在任何情况下,为了将结果发送给调用站点调用完成处理程序 completionHandler 并传递一个结果对象,例如如果它成功保存它的 URL,否则一个 NSError
对象。
现在,由于我们的方法 startUploadSongAnalysis
正在调用异步方法,因此该方法也不可避免地变为异步方法!
如果我对您的原始代码的理解正确,那么您正在递归 调用它以处理大量 Assets 。为了正确实现这一点,您需要进行如下所示的一些修复。生成的“构造”不是递归方法,而是迭代调用异步方法(“异步循环”)。
您可以提供也可以不提供完成处理程序 - 同上。这取决于你 - 但我会推荐它,知道何时处理完所有 Assets 不会有什么坏处。它可能如下所示:
-(void)startUploadSongAnalysisWithCompletion:(completion_t)completionHandler
{
[self updateProgressYForID3NForUpload:NO];
// *** check for break condition: ***
if ([self.uploadWorkingAray count]>=1)
{
... stuff
//export low bitrate song to cache
[self exportAudio:[AVAsset assetWithURL:songU]
toFilePath:savedPath
completion:^(id urlOrError)
{
if ([urlOrError isKindOfClass[NSError class]]) {
// Error occurred:
NSLog(@"Error: %@", urlOrError);
// There are two alternatives to proceed:
// A) Ignore or remember the error and proceed with the next asset.
// In this case, it would be best to have a result array
// containing all the results. Then, invoke
// startUploadSongAnalysisWithCompletion: in order to proceed
// with the next asset.
//
// B) Stop with error.
// Don't call startUploadSongAnalysisWithCompletion: but
// instead invoke the completion handler passing it the error.
// A:
// possibly dispatch to a sync queue or the main thread!
[self.uploadWorkingAray removeObjectAtIndex:0];
[self.songNotFoundArray addObject:songVar];
// *** next song: ***
[self startUploadSongAnalysisWithCompletion:completionHandler];
}
else {
// Success:
// *** next song: ***
NSURL* url = urlOrError;
[self startUploadSongAnalysisWithCompletion:completionHandler];
}
}];
}
else //uploadWorkingAray empty
{
NSLog(@"save changes");
[[VPPCoreData sharedInstance] saveAllChanges];
// *** signal completion ***
if (completionHandler) {
completionHandler(@"OK");
}
}
}
关于ios - 音乐转换以及如何知道是否写入完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20557889/
我有一个 if 语句,如下所示 if (not(fullpath.lower().endswith(".pdf")) or not (fullpath.lower().endswith(tup
然而,在 PHP 中,可以: only appears if $foo is true. only appears if $foo is false. 在 Javascript 中,能否在一个脚
XML有很多好处。它既是机器可读的,也是人类可读的,它具有标准化的格式,并且用途广泛。 它也有一些缺点。它是冗长的,不是传输大量数据的非常有效的方法。 XML最有用的方面之一是模式语言。使用模式,您可
由于长期使用 SQL2000,我并没有真正深入了解公用表表达式。 我给出的答案here (#4025380)和 here (#4018793)违背了潮流,因为他们没有使用 CTE。 我很欣赏它们对于递
我有一个应用程序: void deleteObj(id){ MyObj obj = getObjById(id); if (obj == null) { throw n
我的代码如下。可能我以类似的方式多次使用它,即简单地说,我正在以这种方式管理 session 和事务: List users= null; try{ sess
在开发J2EE Web应用程序时,我通常会按以下方式组织我的包结构 com.jameselsey.. 控制器-控制器/操作转到此处 服务-事务服务类,由控制器调用 域-应用程序使用的我的域类/对象 D
这更多是出于好奇而不是任何重要问题,但我只是想知道 memmove 中的以下片段文档: Copying takes place as if an intermediate buffer were us
路径压缩涉及将根指定为路径上每个节点的新父节点——这可能会降低根的等级,并可能降低路径上所有节点的等级。有办法解决这个问题吗?有必要处理这个吗?或者,也许可以将等级视为树高的上限而不是确切的高度? 谢
我有两个类,A 和 B。A 是 B 的父类,我有一个函数接收指向 A 类型类的指针,检查它是否也是 B 类型,如果是将调用另一个函数,该函数接受一个指向类型 B 的类的指针。当函数调用另一个函数时,我
有没有办法让 valgrind 使用多个处理器? 我正在使用 valgrind 的 callgrind 进行一些瓶颈分析,并注意到我的应用程序中的资源使用行为与在 valgrind/callgrind
假设我们要使用 ReaderT [(a,b)]超过 Maybe monad,然后我们想在列表中进行查找。 现在,一个简单且不常见的方法是: 第一种可能性 find a = ReaderT (looku
我的代码似乎有问题。我需要说的是: if ( $('html').attr('lang').val() == 'fr-FR' ) { // do this } else { // do
根据this文章(2018 年 4 月)AKS 在可用性集中运行时能够跨故障域智能放置 Pod,但尚不考虑更新域。很快就会使用更新域将 Pod 放入 AKS 中吗? 最佳答案 当您设置集群时,它已经自
course | section | type comart2 : bsit201 : lec comart2 :
我正在开发自己的 SDK,而这又依赖于某些第 3 方 SDK。例如 - OkHttp。 我应该将 OkHttp 添加到我的 build.gradle 中,还是让我的 SDK 用户包含它?在这种情况下,
随着 Rust 越来越充实,我对它的兴趣开始激起。我喜欢它支持代数数据类型,尤其是那些匹配的事实,但是对其他功能习语有什么想法吗? 例如标准库中是否有标准过滤器/映射/归约函数的集合,更重要的是,您能
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 关闭 9 年前。 Improve
我一直在研究 PHP 中的对象。我见过的所有示例甚至在它们自己的对象上都使用了对象构造函数。 PHP 会强制您这样做吗?如果是,为什么? 例如: firstname = $firstname;
...比关联数组? 关联数组会占用更多内存吗? $arr = array(1, 1, 1); $arr[10] = 1; $arr[] = 1; // <- index is 11; does the
我是一名优秀的程序员,十分优秀!