avsubtitleWriter demo解析(一):字幕解析
来源:互联网 发布:用qq群推广淘宝客 编辑:程序博客网 时间:2024/05/22 15:33
这是苹果官方的subtitleWriter demo的系列教程。目前关于这部分的材料还不是很多,特地分析源码了解下。
demo下载地址:
https://developer.apple.com/library/mac/samplecode/avsubtitleswriterOSX/Listings/avsubtitleswriter_SubtitlesTextReader_m.html
这是第一篇,字幕解析。
首先引入一个subtitle类,这个类用于从字幕文件中提取字幕信息,并存取。
@interface Subtitle : NSObject+ (instancetype)subtitleWithText:(NSString *)text timeRange:(CMTimeRange)timeRange forced:(BOOL)forced;- (CMFormatDescriptionRef)copyFormatDescription;- (CMSampleBufferRef)copySampleBuffer;@property NSString *text;@property CMTimeRange timeRange;@property BOOL forced;@property CMTextDisplayFlags displayFlags;@end
第一个方法是会在SubtitlesTextReader 调用初始化方法initWithText中被调用,从字幕文件中解析出各部分,然后据此构造字幕对象。
第二第三个方法先留着,暂时不用。
initWithText中解析必要的信息
NSMutableArray *mutableSubtitles = [NSMutableArray array];// Check for a languageNSRegularExpression *languageExpression = [NSRegularExpression regularExpressionWithPattern:@"language: (.*)" options:0 error:nil];NSTextCheckingResult *languageResult = [languageExpression firstMatchInString:text options:0 range:NSMakeRange(0, [text length])];_languageCode = [text substringWithRange:[languageResult rangeAtIndex:1]];// Check for an extended languageNSRegularExpression *extendedLanguageExpression = [NSRegularExpression regularExpressionWithPattern:@"extended language: (.*)" options:0 error:nil];NSTextCheckingResult *extendedLanguageResult = [extendedLanguageExpression firstMatchInString:text options:0 range:NSMakeRange(0, [text length])];_extendedLanguageTag = [text substringWithRange:[extendedLanguageResult rangeAtIndex:1]];// See if SDH has been requestedNSRegularExpression *characteristicsExpression = [NSRegularExpression regularExpressionWithPattern:@"characteristics:.*(SDH)" options:NSRegularExpressionCaseInsensitive error:nil];NSTextCheckingResult *characteristicsResult = [characteristicsExpression firstMatchInString:text options:0 range:NSMakeRange(0, [text length])];_wantsSDH = ([[text substringWithRange:[characteristicsResult rangeAtIndex:1]] caseInsensitiveCompare:@"SDH"] == NSOrderedSame) ? YES : NO;
这边的做法是有待商榷的,你不可能简单从文本去解析字幕的语言,可能需要识别,当然规范的情况下是可以这么做的。
这边解析出三个内容,一是语言代码,二是扩展语言标签,三是SDH标记。你可能不理解第二和第三,第二大概是辅助语言的意思,譬如一部电影,可能对白基本上是英语,但是偶尔出现点法语什么的,那么法语就算是extended language了。至于SDH标记,subtitle for deaf and hard of hearing 听力障碍提示字幕,具体不大清楚,可能就是不固定在下方的一些提示性的字幕吧。
当然这部分不是我们的重点,因为它可能并没多少实际的用处。
下面是解析字幕,是重点,也是有实际意义的。
// Find the subtitle time ranges and text__block int forcedCount = 0;NSRegularExpression *subtitlesExpression = [NSRegularExpression regularExpressionWithPattern:@"(..):(..):(..),(...) --> (..):(..):(..),(...)( !!!)?\n(.*)" options:0 error:nil];[subtitlesExpression enumerateMatchesInString:text options:0 range:NSMakeRange(0, [text length]) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {// Get the textNSString *subtitleText = [text substringWithRange:[result rangeAtIndex:10]];// Create the time rangedouble startTime = ([[text substringWithRange:[result rangeAtIndex:1]] doubleValue] * 60.0 * 60.0) + ([[text substringWithRange:[result rangeAtIndex:2]] doubleValue] * 60.0) + [[text substringWithRange:[result rangeAtIndex:3]] doubleValue] + ([[text substringWithRange:[result rangeAtIndex:4]] doubleValue] / 1000.0);double endTime = ([[text substringWithRange:[result rangeAtIndex:5]] doubleValue] * 60.0 * 60.0) + ([[text substringWithRange:[result rangeAtIndex:6]] doubleValue] * 60.0) + [[text substringWithRange:[result rangeAtIndex:7]] doubleValue] + ([[text substringWithRange:[result rangeAtIndex:8]] doubleValue] / 1000.0);CMTimeRange timeRange = CMTimeRangeMake(CMTimeMakeWithSeconds(startTime, 600), CMTimeMakeWithSeconds(endTime - startTime, 600));// Is it forced?BOOL forced = NO;if (([result rangeAtIndex:9].length > 0) && [[text substringWithRange:[result rangeAtIndex:9]] isEqualToString:@" !!!"]){forced = YES;forcedCount++;}// Stash a Subtitle object for later use by -copyNextSampleBuffer[mutableSubtitles addObject:[Subtitle subtitleWithText:subtitleText timeRange:timeRange forced:forced]];}];
这里使用了正则表达式,其中
NSRegularExpression *subtitlesExpression = [NSRegularExpression regularExpressionWithPattern:@"(..):(..):(..),(...) --> (..):(..):(..),(...)( !!!)?\n(.*)" options:0 error:nil];
这一句是我们要匹配的表达式,代表了一行时间轴以及对应的字幕。每个括号代表一个子表达式。
接着,我们处理子表达式
[subtitlesExpression enumerateMatchesInString:text options:0 range:NSMakeRange(0, [text length]) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {}];
这个方法是获取一条字幕以时间轴,再在block中进行子查询。所有子表达式的结果存放在result中,它其实可以认为是个NSRange数组。使用rangeatindex取出每个子表达式匹配的结果,结果是一个nsrange,反应了它在字符串中的位置和长度。值得注意的是,index 0代表的是整条正则的匹配结果,从1开始才是子表达式的匹配结果。
在本例中,前面四个括号分别对应index 1,2,3,4,表示时,分,秒,毫秒,其中秒和毫秒之间用逗号分隔。可以据此计算出开始的时间,以秒为单位。同理也能计算出结束时间。下标是9的是字符串“!!!”或者没有,前者表示该字幕是强制字幕,后者表示没有该属性。强制字幕就是即使你切换也会强制显示的字幕。下标10是我们的字幕。
最后调用下面的方法打包。
+ (instancetype)subtitleWithText:(NSString *)text timeRange:(CMTimeRange)timeRange forced:(BOOL)forced;
接下来是设置字幕显示标志,也就是是否强制,单独放出来,是因为要做整体性的判断。
// Set forced subtitles display flags as appropriate.if ([mutableSubtitles count] == forcedCount){for (Subtitle *subtitle in mutableSubtitles){subtitle.displayFlags = kCMTextDisplayFlag_forcedSubtitlesPresent | kCMTextDisplayFlag_allSubtitlesForced;}}else if (forcedCount > 0){for (Subtitle *subtitle in mutableSubtitles){subtitle.displayFlags = kCMTextDisplayFlag_forcedSubtitlesPresent;}}_subtitles = [mutableSubtitles copy];
这边,如果每条字幕都是强制的,那么我们设置显示标记为kCMTextDisplayFlag_forcedSubtitlesPresent | kCMTextDisplayFlag_allSubtitlesForced,意思是所有字母都强制或者根据每条字幕自身属性而定。如果不是所有字幕都是强制的,那么设置为kCMTextDisplayFlag_forcedSubtitlesPresent,表明依据每条字幕的实际情况选择是否强制。现在我们的SubtitlesTextReader 已经拥有了一个字幕数组。
- avsubtitleWriter demo解析(一):字幕解析
- avsubtitleWriter demo解析(三):SubtitlesTextReader
- avsubtitleWriter demo解析(二):创建CMSampleBufferRef
- avsubtitleWriter demo解析(四):writeSubtitles上篇
- avsubtitleWriter demo解析(四):writeSubtitles下篇
- Android 解析smi字幕
- srt字幕解析
- srt字幕解析(上)
- Android解析SRT字幕文件
- MediaPlayer 同步加载字幕 与 手动解析字幕
- SRT视频字幕的解析与同步
- ssa/ass字幕格式全解析
- demo-rgbd论文解析+代码分析(一)
- 背景 - JasperReports Demo解析
- linux socket 解析 & demo
- Jsoup解析HTML Demo
- android api demo 解析
- ActivityLifeCycle官方demo解析
- 设置圆形按钮
- epoll和select性能比较
- Java的内存管理
- 新的开始
- 无线网络的负载均衡
- avsubtitleWriter demo解析(一):字幕解析
- Mockito: InvalidUseOfMatchersException
- Python - 快速排序(quick sort) 及 去重(no duplicate)
- [Maven]添加新仓库或者新发布依赖后却获取不到问题的解决方案
- 深入理解JVM
- 案例:区分项目类型建立过程性能模型
- 3.1-3.31推荐文章汇总
- C# 用数据库读取Excel出现“定义了过多字段”错误的解决方法
- 802.11 PCF/DCF