Objective c 如何使用强制(MP3)类型从URL播放QTMovie文件?
我正在使用QTKit逐步从URL下载并播放MP3。根据,这是我应该用来实现以下目标的代码:Objective c 如何使用强制(MP3)类型从URL播放QTMovie文件?,objective-c,cocoa,mp3,qtkit,progressive-download,Objective C,Cocoa,Mp3,Qtkit,Progressive Download,我正在使用QTKit逐步从URL下载并播放MP3。根据,这是我应该用来实现以下目标的代码: NSURL *mp3URL = [NSURL URLWithString:@"http://foo.com/bar.mp3"]; NSError *error = nil; QTMovie *sound = [[QTMovie alloc] initWithURL:mp3URL error:&error]; [sound play]; 这是可行的,并且完全符合我的要求——M
NSURL *mp3URL = [NSURL URLWithString:@"http://foo.com/bar.mp3"];
NSError *error = nil;
QTMovie *sound = [[QTMovie alloc] initWithURL:mp3URL error:&error];
[sound play];
这是可行的,并且完全符合我的要求——MP3 URL被延迟下载并立即开始播放。但是,如果URL没有“.mp3”路径扩展名,则会失败:
NSURL *mp3URL = [NSURL URLWithString:@"http://foo.com/bar"];
NSError *error = nil;
QTMovie *sound = [[QTMovie alloc] initWithURL:mp3URL error:&error];
[sound play];
未给出错误,未引发异常;声音的持续时间刚刚设置为零,什么也不播放
我发现解决此问题的唯一方法是通过手动加载数据并使用QTDataReference强制类型:
NSURL *mp3URL = [NSURL URLWithString:@"http://foo.com/bar"];
NSData *mp3Data = [NSData dataWithContentsOfURL:mp3URL];
QTDataReference *dataReference =
[QTDataReference dataReferenceWithReferenceToData:mp3Data
name:@"bar.mp3"
MIMEType:nil];
NSError *error = nil;
QTMovie *sound = [[QTMovie alloc] initWithDataReference:dataReference error:&error];
[sound play];
然而,这迫使我在开始播放之前完全同步下载所有MP3,这显然是不可取的。这有什么办法吗
谢谢
编辑
实际上,路径扩展似乎与此无关;HTTP头中没有设置内容类型。即便如此,后一种代码仍然有效,而前一种代码则不然。有人知道一种不用访问服务器就能解决这个问题的方法吗
编辑2
有人吗?我在任何地方都找不到这方面的信息,令人沮丧的是,谷歌现在将此页面显示为我大多数查询的最佳结果…两个想法。(第一个有点老套):为了解决缺少的内容类型,您可以嵌入一个小型Cocoa Web服务器来补充缺少的头字段,并通过该“代理”路由NSURL 一些http服务器实现:
您需要更多的代码,但关于如何使用AudioToolbox流式播放mp3,有一些非常好的资源。
例如。: 就我个人而言,我会选择第二种选择。AudioToolbox不像QTKit那么简单,但它为您的问题提供了一个干净的解决方案。它在iOS和Mac操作系统上都可用,所以你会发现很多信息 更新:
您是否尝试使用其他初始值设定项?e、 g
+ (id)movieWithAttributes:(NSDictionary *)attributes error:(NSError **)errorPtr
您可以为keyqtmovieurldattribute
插入URL,也可以通过在该字典中提供其他属性来补偿缺少的内容类型。
此开源项目有一个QTMovie类别,其中包含完成类似任务的方法:
如果你认为第一个解决方案是黑客的,你会喜欢这个:
罪魁祸首是内容类型
标题,正如您所确定的。如果QTKit.framework
在内部使用Objective-C,那么用您选择的类别覆盖-[NSHTTPURLResponse allHeaderFields]
将是一件小事。但是,typedef struct interpose_s {
void *new_func;
void *orig_func;
} interpose_t;
CFStringRef myCFHTTPMessageCopyHeaderFieldValue (
CFHTTPMessageRef message,
CFStringRef headerField
);
static const interpose_t interposers[] __attribute__ ((section("__DATA, __interpose"))) = {
{ (void *)myCFHTTPMessageCopyHeaderFieldValue, (void *)CFHTTPMessageCopyHeaderFieldValue }
};
CFStringRef myCFHTTPMessageCopyHeaderFieldValue (
CFHTTPMessageRef message,
CFStringRef headerField
) {
if (CFStringCompare(headerField, CFSTR("Content-Type"), 0) == kCFCompareEqualTo) {
return CFSTR("audio/x-mpeg");
} else {
return CFHTTPMessageCopyHeaderFieldValue(message, headerField);
}
}
您可能希望在处理
内容类型字段方面为应用程序添加特定的逻辑,以免当每个HTTP请求都被确定为音频文件时,应用程序以奇怪的方式崩溃。尝试将HTTP://
替换为icy://
只需创建一个这样的实例
QTMovie *aPlayer = [QTMovie movieWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
fileUrl, QTMovieURLAttribute,
[NSNumber numberWithBool:YES], QTMovieOpenForPlaybackAttribute,
/*[NSNumber numberWithBool:YES], QTMovieOpenAsyncOKAttribute,*/
nil] error:error];
AddioStuffER看起来很有前途,但不幸的是,它似乎不适用于我的用例,因为我经常收到一个“无法配置的网络读流”后暂停,然后在MP3的中间播放。(因此,我正在寻找渐进式下载器而不是拖缆。)此外,“AudioToolbox并不像QTKit那么简单“有点轻描淡写,不是吗?核心音频经常被引用为最重要的音频,我敢肯定这是最容易被微妙地滥用的音频之一。由于我所做的工作相对简单,我更愿意将繁重的工作留给“做得对”的更高级别API来完成。”。是的,核心音频很难,我完全理解您首先查看高级API。我用另一个想法更新了我的原始答案。(虽然没有测试。您可以发布一些有问题的URL吗?)感谢您的帮助和进一步建议;但不幸的是,我得到了相同的结果。下面是一个“坏”URL的示例: