Skip to content

Commit

Permalink
mkv-embedded-subtitle loading bug fixed
Browse files Browse the repository at this point in the history
- libebml::StdIOCallback has 32-bit-fseek problem.
  so, we use custom IO class for file operations.
- save time for no subtitle embedded.

if subtitle file exist but no subtitle found,
then info-message is now displayed as alert-panel.



git-svn-id: http://movist.googlecode.com/svn/trunk@233 9988c26d-9134-0410-b5bb-5778289bb252
  • Loading branch information
cocoable committed Feb 9, 2009
1 parent 8949d16 commit 4d942ff
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 55 deletions.
64 changes: 42 additions & 22 deletions AppController_Open.m
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ - (NSString*)subtitleInfoMessageString
}
}
if (!s) {
s = NSLocalizedString(@"No Subtitle: Reopen with other encodings", nil);
s = NSLocalizedString(@"Cannot Read Subtitle", nil);
}
}
return s;
Expand Down Expand Up @@ -344,27 +344,46 @@ - (BOOL)openMovie:(NSURL*)movieURL movieClass:(Class)movieClass
}

// open subtitles
if ([_defaults boolForKey:MAutoLoadMKVEmbeddedSubtitlesKey]) {
NSString* ext = [[[movieURL path] pathExtension] lowercaseString];
if ([ext isEqualToString:@"mkv"]) {
NSMutableArray* URLs = [NSMutableArray arrayWithArray:subtitleURLs];
[URLs addObject:movieURL];
subtitleURLs = URLs;
}
}
if (0 < [subtitleURLs count] && [_defaults boolForKey:MSubtitleEnableKey]) {
NSArray* subtitles = [self subtitleFromURLs:subtitleURLs
withEncoding:subtitleEncoding error:&error];
if (!subtitles) {
NSURL* subtitleURL;
NSEnumerator* e = [subtitleURLs objectEnumerator];
while (subtitleURL = [e nextObject]) {
runAlertPanelForOpenError(_mainWindow, error, subtitleURL);
if ([_defaults boolForKey:MSubtitleEnableKey]) {
NSMutableArray* subtitles = [NSMutableArray arrayWithCapacity:1];
// load mkv-embedded subtitles
if ([_defaults boolForKey:MAutoLoadMKVEmbeddedSubtitlesKey]) {
NSString* ext = [[[movieURL path] pathExtension] lowercaseString];
if ([ext isEqualToString:@"mkv"]) {
NSArray* subs = [self subtitleFromURL:movieURL
withEncoding:subtitleEncoding error:&error];
if (!subs) {
runAlertPanelForOpenError(_mainWindow, error, movieURL);
// continue... subtitle is not necessary for movie.
}
else {
[subtitles addObjectsFromArray:subs];
}
}
// continue... subtitle is not necessary for movie.
}
else {
_subtitles = [[NSMutableArray alloc] initWithArray:subtitles];
// load external subtitle files
if (0 < [subtitleURLs count]) {
NSArray* subs = [self subtitleFromURLs:subtitleURLs
withEncoding:subtitleEncoding error:&error];
if (!subs) {
NSURL* subtitleURL;
NSEnumerator* e = [subtitleURLs objectEnumerator];
while (subtitleURL = [e nextObject]) {
runAlertPanelForOpenError(_mainWindow, error, subtitleURL);
}
// continue... subtitle is not necessary for movie.
}
else if ([subs count] == 0) {
runAlertPanel(_mainWindow, NSLocalizedString(@"Cannot Read Subtitle", nil),
NSLocalizedString(@"Reopen with other encodings", nil),
NSLocalizedString(@"OK", nil), nil, nil);
}
else {
[subtitles addObjectsFromArray:subs];
}
}
if (0 < [subtitles count]) {
_subtitles = [subtitles retain];
[self updateExternalSubtitleTrackNames];
if (!isSeries) {
// if not same movie series, then clear previous subtitle info.
Expand All @@ -373,7 +392,6 @@ - (BOOL)openMovie:(NSURL*)movieURL movieClass:(Class)movieClass
[self autoenableSubtitles];
}
}

[self updateUIForOpenedMovieAndSubtitle:isSeries];
_checkForAltVolumeChange = TRUE;

Expand Down Expand Up @@ -477,7 +495,9 @@ - (BOOL)openSubtitles:(NSArray*)subtitleURLs encoding:(CFStringEncoding)encoding
// if this is reopening with other encoding and no subtitle in subtitleURLs,
// then, don't reset current subtitles for trials with other encodings.
// FIXME: show all subtitleURLs...
NSString* s = NSLocalizedString(@"No Subtitle: Reopen with other encodings", nil);
NSString* s = [NSString stringWithFormat:@"%@: %@",
NSLocalizedString(@"Cannot Read Subtitle", nil),
NSLocalizedString(@"Reopen with other encodings", nil)];
[_movieView setMessageWithURL:[subtitleURLs objectAtIndex:0] info:s];
return FALSE;
}
Expand Down
3 changes: 2 additions & 1 deletion English.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@
"Hue %.2f" = "Hue %.2f";

/* Message: Subtitle */
"No Subtitle: Reopen with other encodings" = "No Subtitle: Reopen with other encodings";
"Cannot Read Subtitle" = "Cannot Read Subtitle";
"Reopen with other encodings" = "Reopen with other encodings";
"Letter Box Height : Auto" = "Letter Box Height : Auto";
"Font Size" = "Font Size";
"HMargin" = "HMargin";
Expand Down
Binary file modified Korean.lproj/Localizable.strings
Binary file not shown.
13 changes: 8 additions & 5 deletions MSubtitle.m
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,15 @@ - (NSString*)summary

- (BOOL)checkDefaultLanguage:(NSArray*)defaultLangIDs
{
NSString* s;
#define CHECK_SUBSTRING(field, identifier) \
(field && [field rangeOfString:identifier \
options:NSCaseInsensitiveSearch].location != NSNotFound)
NSString* identifier;
NSEnumerator* e = [defaultLangIDs objectEnumerator];
while (s = [e nextObject]) {
if ([_name rangeOfString:s options:NSCaseInsensitiveSearch].location != NSNotFound ||
[_language rangeOfString:s options:NSCaseInsensitiveSearch].location != NSNotFound ||
[_extraInfo rangeOfString:s options:NSCaseInsensitiveSearch].location != NSNotFound) {
while (identifier = [e nextObject]) {
if (CHECK_SUBSTRING(_name, identifier) ||
CHECK_SUBSTRING(_language, identifier) ||
CHECK_SUBSTRING(_extraInfo, identifier)) {
return TRUE;
}
}
Expand Down
4 changes: 3 additions & 1 deletion MSubtitleParser_MKV.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ namespace libebml {
namespace libmatroska {
class KaxCluster;
}
class StdIOCallback64;
#endif

@class MSubtitleParser_SRT;
Expand All @@ -43,7 +44,8 @@ namespace libmatroska {
NSMutableDictionary* _subtitles;

#if defined(__cplusplus)
libebml::StdIOCallback* _file;
//libebml::StdIOCallback* _file; // libebml::StdIOCallback has 32-bit-fseek() problem.
StdIOCallback64* _file; // so, we use custom IO class for file operations.
libebml::EbmlStream* _stream;
libebml::EbmlElement* _level0;
libebml::EbmlElement* _level1;
Expand Down
87 changes: 61 additions & 26 deletions MSubtitleParser_MKV.mm
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,11 @@ - (void)dealloc
[super dealloc];
}

- (void)addSubtitleWithNumber:(int)number
- (MSubtitle*)addSubtitleWithNumber:(int)number
{
[_subtitles setObject:[[[MSubtitle alloc] initWithURL:_subtitleURL] autorelease]
forKey:[NSNumber numberWithInt:number]];
MSubtitle* subtitle = [[MSubtitle alloc] initWithURL:_subtitleURL];
[_subtitles setObject:subtitle forKey:[NSNumber numberWithInt:number]];
return [subtitle autorelease];
}

- (MSubtitle*)subtitleWithNumber:(int)number
Expand All @@ -103,22 +104,22 @@ - (NSArray*)allSubtitles
{
NSMutableArray* numbers = [NSMutableArray arrayWithArray:[_subtitles allKeys]];
[numbers sortUsingSelector:@selector(compare:)];

NSMutableArray* subtitles = [NSMutableArray arrayWithCapacity:[numbers count]];

int trackNumber = 1;
NSNumber* number;
MSubtitle* subtitle;
int track = 1;
NSNumber* num;
MSubtitle* sub;
NSEnumerator* e = [numbers objectEnumerator];
while (number = [e nextObject]) {
subtitle = [_subtitles objectForKey:number];
[subtitle setTrackName:(1 == [numbers count]) ?
NSLocalizedString(@"Subtitle Track", nil) :
[NSString stringWithFormat:@"%@ %d",
NSLocalizedString(@"Subtitle Track", nil), trackNumber]];
[subtitle setEmbedded:TRUE];
[subtitles addObject:subtitle];
trackNumber++;
while (num = [e nextObject]) {
sub = [_subtitles objectForKey:num];
[sub setTrackName:(1 == [numbers count]) ?
NSLocalizedString(@"Subtitle Track", nil) :
[NSString stringWithFormat:@"%@ %d",
NSLocalizedString(@"Subtitle Track", nil), track]];
[sub setEmbedded:TRUE];
[subtitles addObject:sub];
track++;
}
return subtitles;
}
Expand Down Expand Up @@ -179,7 +180,7 @@ - (void)readMaster:(EbmlMaster*)master
- (void)parseInfo
{
// General info about this Matroska _file
TRACE_ELEMENT(_level1, 1, @"Segment information");
TRACE_ELEMENT(_level1, 1, @"Segment Information");

_upperLevel = 0;
EbmlMaster* master = static_cast<EbmlMaster*>(_level1);
Expand All @@ -197,7 +198,7 @@ - (void)parseInfo

- (void)parseTracks
{
TRACE_ELEMENT(_level1, 1, @"Segment tracks");
TRACE_ELEMENT(_level1, 1, @"Segment Tracks");

_upperLevel = 0;
EbmlMaster* master1 = static_cast<EbmlMaster*>(_level1);
Expand Down Expand Up @@ -225,8 +226,7 @@ - (void)parseTracks
else {
TRACE_ELEMENT(_level2, 2, @"Track");
TRACE_ELEMENT(_level3, 3, @"Track Type: subtitles");
[self addSubtitleWithNumber:trackNumber];
subtitle = [self subtitleWithNumber:trackNumber];
subtitle = [self addSubtitleWithNumber:trackNumber];
}
}
else if (subtitle && is_id(_level3, KaxTrackName)) {
Expand Down Expand Up @@ -283,10 +283,10 @@ - (void)parseBlockGroup
if (subtitle) {
if (!blockGroupPrinted) {
blockGroupPrinted = TRUE;
TRACE_ELEMENT(_level2, 2, @"Block group");
TRACE_ELEMENT(_level2, 2, @"Block Group");
}
TRACE_ELEMENT(_level3, 3,
@"Block (track#= %u, %u frame(s), timecode %f sec = %s)",
@"Block: track#=%u, %u frame(s), timecode=%f (%s)",
block.TrackNum(), block.NumberFrames(),
((float)block.GlobalTimecode() / 1000000000.0),
format_timecode(block.GlobalTimecode()).c_str());
Expand Down Expand Up @@ -327,7 +327,7 @@ - (void)parseBlockGroup
[subtitle addString:_string beginTime:_beginTime endTime:_beginTime + d];
_string = nil;
}
TRACE_ELEMENT(_level3, 3, @"Block duration: %llu.%llu ms",
TRACE_ELEMENT(_level3, 3, @"Block Duration: %llu.%llu ms",
(uint64(duration) * _timecodeScale / 1000000),
(uint64(duration) * _timecodeScale % 1000000));
}
Expand Down Expand Up @@ -357,27 +357,58 @@ - (void)parseCluster
}
}

////////////////////////////////////////////////////////////////////////////////
// custom IO class

class StdIOCallback64 : public IOCallback {
public:
StdIOCallback64(NSString* path, BOOL readOnly = TRUE)
{ _file = ::open([path UTF8String], (readOnly) ? O_RDONLY : O_RDWR); }
virtual ~StdIOCallback64() { close(); }

private:
int _file; // file descriptor
public:
virtual uint64 getFilePointer() { return ::lseek(_file, 0, SEEK_CUR); }
virtual void setFilePointer(int64_t offset, seek_mode mode = seek_beginning);
virtual uint32 read(void* p, size_t size) { return ::read(_file, p, size); }
virtual size_t write(const void* p, size_t size) { return ::write(_file, p, size); }
virtual void close() { ::close(_file); }
};

void StdIOCallback64::setFilePointer(int64_t offset, seek_mode mode)
{
switch (mode) {
case seek_beginning : ::lseek(_file, offset, SEEK_SET); break;
case seek_end : ::lseek(_file, offset, SEEK_END); break;
default :
::lseek(_file, lseek(_file, 0, SEEK_END) + offset, SEEK_SET);
break;
}
}

////////////////////////////////////////////////////////////////////////////////

- (BOOL)initEbmlStream
{
NSString* path = [_subtitleURL path];
_file = new StdIOCallback([path UTF8String], MODE_READ);
//_file = new StdIOCallback([path UTF8String], MODE_READ);
_file = new StdIOCallback64(path);
_stream = new EbmlStream(*_file);
_level0 = _level1 = _level2 = _level3 = 0;
_timecodeScale = 1000000; // default scale

// Find the EbmlHead element. Must be the first one.
_level0 = _stream->FindNextID(EbmlHead::ClassInfos, 0xFFFFFFFFL);
if (!_level0) {
TRACE(@"No EBML head found.");
TRACE(@"No EBML Head found.");
delete _stream, _stream = 0;
delete _file, _file = 0;
return FALSE;
}

// skip header
TRACE_ELEMENT(_level0, 0, @"EBML head");
TRACE_ELEMENT(_level0, 0, @"EBML Head");
_level0->SkipData(*_stream, _level0->Generic().Context);
delete _level0, _level0 = 0;

Expand Down Expand Up @@ -418,6 +449,10 @@ - (NSArray*)parseWithOptions:(NSDictionary*)options error:(NSError**)error
}
else if (is_id(_level1, KaxTracks)) {
[self parseTracks]; // find subtitle tracks
if ([_subtitles count] == 0) { // if no subtitle track found,
delete _level1, _level1 = 0; // then, need not read more.
break;
}
}
else if (is_id(_level1, KaxCluster)) {
[self parseCluster]; // get subtitles
Expand Down

0 comments on commit 4d942ff

Please sign in to comment.