Changeset 333

Show
Ignore:
Timestamp:
02/08/07 02:35:51 (2 years ago)
Author:
astrange
Message:

Apply overlap handling to Matroska.
This should make the vast majority of files playable.
Refs #17

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/MatroskaImport.cpp

    r302 r333  
    271271                        if (!NextLevel1Element()) 
    272272                                *outFlags |= movieImportResultComplete; 
    273                         else 
     273                        else { 
    274274                                *outFlags |= movieImportResultNeedIdles; 
     275                                return noErr; 
     276                        } 
    275277                         
    276                         return noErr; 
    277278                } 
    278279                 
     
    291292                // insert the a/v tracks' samples 
    292293                for (int i = 0; i < tracks.size(); i++) 
    293                         tracks[i].AddSamplesToTrack(); 
     294                        tracks[i].FinishTrack(); 
    294295                 
    295296        } catch (CRTError &err) { 
     
    336337                *outFlags |= movieImportResultComplete; 
    337338                loadState = kMovieLoadStateComplete; 
     339                 
     340                for (int i = 0; i < tracks.size(); i++) 
     341                        tracks[i].FinishTrack(); 
    338342        } 
    339343         
  • trunk/MatroskaImport.h

    r323 r333  
    2929#include <QuickTime/QuickTime.h> 
    3030#include "DataHandlerCallback.h" 
     31#include "SubImport.h" 
    3132 
    3233#include <ebml/EbmlStream.h> 
     
    4950        SInt64                  size; 
    5051        short                   flags; 
     52        DataBuffer         *buffer; 
    5153}; 
    5254 
     
    6971        // added, e.g. from a previous call to AddSamplesToTrack() 
    7072        void AddSamplesToTrack(); 
     73         
     74        void FinishTrack(); 
    7175         
    7276        UInt16                                  number; 
     
    7983        SInt64                                  timecodeScale; 
    8084        TimeValue64                             maxLoadedTime; 
     85        CXXSubtitleSerializer   *subtitleSerializer; 
     86        Handle                                  subDataRefHandler; 
    8187         
    8288private: 
  • trunk/MatroskaImportPrivate.cpp

    r328 r333  
    463463        } else if ((*imgDesc)->cType == kSubFormatUTF8 || (*imgDesc)->cType == kSubFormatSSA || (*imgDesc)->cType == kSubFormatASS) { 
    464464                if ((*imgDesc)->cType == kSubFormatASS) (*imgDesc)->cType = kSubFormatSSA; // no real reason to treat them differently 
    465                  
    466                 mkvTrack.theTrack = CreatePlaintextSubTrack(theMovie, imgDesc, GetMovieTimeScale(theMovie), dataRef, dataRefType, (*imgDesc)->cType, NULL, movieBox); 
     465                UInt32 emptyDataRefExtension[2]; // XXX the various uses of this bit of code should be unified 
     466                mkvTrack.subDataRefHandler = NewHandleClear(sizeof(Handle) + 1); 
     467                emptyDataRefExtension[0] = EndianU32_NtoB(sizeof(UInt32)*2); 
     468                emptyDataRefExtension[1] = EndianU32_NtoB(kDataRefExtensionInitializationData); 
     469                 
     470                PtrAndHand(&emptyDataRefExtension[0], mkvTrack.subDataRefHandler, sizeof(emptyDataRefExtension)); 
     471                 
     472                mkvTrack.theTrack = CreatePlaintextSubTrack(theMovie, imgDesc, GetMovieTimeScale(theMovie), mkvTrack.subDataRefHandler, HandleDataHandlerSubType, (*imgDesc)->cType, NULL, movieBox); 
    467473                if (mkvTrack.theTrack == NULL) 
    468474                        return GetMoviesError(); 
     
    471477                mh = GetMediaHandler(mkvTrack.theMedia); 
    472478                MediaSetGraphicsMode(mh, graphicsModePreBlackAlpha, NULL); 
     479                 
     480                BeginMediaEdits(mkvTrack.theMedia); 
    473481        } else { 
    474482                Codecprintf(NULL, "MKV: Unsupported subtitle type\n"); 
     
    580588        while (attachedFile && attachedFile->GetSize() > 0) { 
    581589                string fileMimeType = GetChild<KaxMimeType>(*attachedFile); 
    582                  
    583                 if (fileMimeType == "application/x-truetype-font") { 
     590                /* The only attachments handled here are fonts, which currently can be truetype or opentype. 
     591                   application/x-* is probably not a permanent MIME type, but it is current practice... */ 
     592                if (fileMimeType == "application/x-truetype-font" || fileMimeType == "application/x-font-otf") { 
    584593                        KaxFileData & fontData = GetChild<KaxFileData>(*attachedFile); 
    585594                         
     
    641650        firstSample = -1; 
    642651        amountToAdd = 0; 
     652        subtitleSerializer = new CXXSubtitleSerializer; 
     653        subDataRefHandler = NULL; 
    643654} 
    644655 
     
    670681        firstSample = copy.firstSample; 
    671682        amountToAdd = copy.amountToAdd; 
     683         
     684        subtitleSerializer = copy.subtitleSerializer; 
     685        subtitleSerializer->retain(); 
     686                 
     687        subDataRefHandler = copy.subDataRefHandler; 
    672688} 
    673689 
     
    679695        if (sampleTable) 
    680696                QTSampleTableRelease(sampleTable); 
     697         
     698        if (subtitleSerializer) 
     699                subtitleSerializer->release(); 
    681700} 
    682701 
     
    729748                newFrame.size = block.GetFrameSize(i); 
    730749                newFrame.flags = blockGroup.ReferenceCount() > 0 ? mediaSampleNotSync : 0; 
    731                  
    732                 if (type == track_subtitle) 
     750 
     751                if (type == track_subtitle) { 
     752                        newFrame.buffer = &block.GetBuffer(i); 
    733753                        AddFrame(newFrame); 
     754                } 
    734755                else 
    735756                        lastFrames.push_back(newFrame); 
     757                 
     758                newFrame.buffer = NULL; 
    736759        } 
    737760} 
     
    743766        TimeValue sampleTime; 
    744767         
    745         if (sampleTable) { 
     768        if (type == track_subtitle) { 
     769                if (frame.size > 0) subtitleSerializer->pushLine((const char*)frame.buffer->Buffer(), frame.buffer->Size(), frame.timecode, frame.timecode + frame.duration); 
     770                const char *packet=NULL; size_t size=0; unsigned start=0, end=0; 
     771                packet = subtitleSerializer->popPacket(&size, &start, &end); 
     772                if (packet) { 
     773                        Handle sampleH; 
     774                        PtrToHand(packet, &sampleH, size); 
     775                        err = AddMediaSample(theMedia, sampleH, 0, size, end - start, desc, 1, 0, &sampleTime); 
     776                        if (err) { 
     777                                Codecprintf(NULL, "MKV: error adding subtitle sample %d\n", err); 
     778                                return; 
     779                        } 
     780                        DisposeHandle(sampleH); 
     781                        frame.timecode = start; 
     782                        frame.duration = end - start; 
     783                        sampleNum = sampleTime; 
     784                } else return; 
     785        } else if (sampleTable) { 
    746786                err = QTSampleTableAddSampleReferences(sampleTable, frame.offset, frame.size, frame.duration,  
    747787                                                                                           0, 1, frame.flags, qtSampleDesc, &sampleNum); 
     
    773813        if (type == track_subtitle) { 
    774814                if (sampleTable) { 
    775                         // subtitle tracks shouldn't need sample tables, but just in case... 
    776                         TimeValue64 sampleTime64; 
    777                         err = AddSampleTableToMedia(theMedia, sampleTable, sampleNum, 1, &sampleTime64); 
    778                         sampleTime = sampleTime64; 
    779                         if (err) { 
    780                                 Codecprintf(NULL, "MKV: error adding sample table to media for subtitle %d\n", err); 
    781                                 return; 
    782                         } 
     815                        Codecprintf(NULL, "MKV: subtitle track has a sample table\n", err); 
     816                        return; 
    783817                } 
    784818                err = InsertMediaIntoTrack(theTrack, frame.timecode, sampleTime, frame.duration, fixed1); 
     
    797831        OSStatus err = noErr; 
    798832         
    799         if (type == track_subtitle) 
    800                 // subtitle tracks add the media in AddFrame() since there's gaps 
    801                 return; 
    802          
    803         if (sampleTable) { 
    804                 TimeValue64 sampleTime64; 
    805                 TimeValue mediaDuration = GetMediaDuration(theMedia); 
    806                  
    807                 err = AddSampleTableToMedia(theMedia, sampleTable, firstSample, amountToAdd, &sampleTime64); 
     833        if (type != track_subtitle) { 
     834                if (sampleTable) { 
     835                        TimeValue64 sampleTime64; 
     836                        TimeValue mediaDuration = GetMediaDuration(theMedia); 
     837                         
     838                        err = AddSampleTableToMedia(theMedia, sampleTable, firstSample, amountToAdd, &sampleTime64); 
     839                        if (err) 
     840                                Codecprintf(NULL, "MKV: error adding sample table to media %d\n", err); 
     841                         
     842                        firstSample = sampleTime64; 
     843                        amountToAdd = GetMediaDuration(theMedia) - mediaDuration; 
     844                } 
     845                err = InsertMediaIntoTrack(theTrack, -1, firstSample, amountToAdd, fixed1); 
    808846                if (err) 
    809                         Codecprintf(NULL, "MKV: error adding sample table to media %d\n", err); 
    810                  
    811                 firstSample = sampleTime64; 
    812                 amountToAdd = GetMediaDuration(theMedia) - mediaDuration; 
    813         } 
    814         err = InsertMediaIntoTrack(theTrack, -1, firstSample, amountToAdd, fixed1); 
    815         if (err) 
    816                 Codecprintf(NULL, "MKV: error inserting media into track %d\n", err); 
    817          
     847                        Codecprintf(NULL, "MKV: error inserting media into track %d\n", err); 
     848        } 
     849 
    818850        maxLoadedTime += amountToAdd; 
    819851        firstSample = -1; 
    820852        amountToAdd = 0; 
    821853} 
     854 
     855void MatroskaTrack::FinishTrack() 
     856{ 
     857        OSStatus err = noErr; 
     858         
     859        if (type == track_subtitle) 
     860        { 
     861                 subtitleSerializer->setFinished(); 
     862                 do { 
     863                         MatroskaFrame fr = {0}; 
     864                         AddFrame(fr); // add empty frames to flush the subtitle packet queue 
     865                 } while (!subtitleSerializer->empty()); 
     866                 EndMediaEdits(theMedia); 
     867        } 
     868         
     869        AddSamplesToTrack(); 
     870} 
  • trunk/SubImport.h

    r330 r333  
    4848} 
    4949-(void)addLine:(SubLine *)sline; 
    50 -(void)addLineWithString:(NSString*)string start:(unsigned)start end:(unsigned)end; 
    5150-(void)setFinished:(BOOL)finished; 
    5251-(SubLine*)getSerializedPacket; 
     
    5453#endif 
    5554 
     55#ifdef __cplusplus 
     56class CXXSubtitleSerializer 
     57{ 
     58        void *priv; 
     59         
     60public: 
     61        CXXSubtitleSerializer(); 
     62        ~CXXSubtitleSerializer(); 
     63         
     64        void pushLine(const char *line, size_t size, unsigned start, unsigned end); 
     65        void setFinished(); 
     66        const char *popPacket(size_t *size, unsigned *start, unsigned *end); 
     67        void release(); 
     68        void retain(); 
     69        bool empty(); 
     70}; 
    5671#endif 
     72#endif 
  • trunk/SubImport.mm

    r332 r333  
    355355} 
    356356 
    357 -(void)addLineWithString:(NSString*)string start:(unsigned)start end:(unsigned)end 
    358 { 
    359         SubLine *sl = [[[SubLine alloc] init] autorelease]; 
    360          
    361         sl->line = [string retain]; 
    362         sl->begin_time = start; 
    363         sl->end_time = end; 
    364          
    365         [lines addObject:sl]; 
    366 } 
    367  
    368357static int cmp_line(id a, id b, void* unused) 
    369358{                        
     
    396385{ 
    397386        unsigned num = [lines count]; 
     387        if (num == 0) return; 
    398388        unsigned times[num*2+1]; 
    399389        SubLine *slines[num]; 
    400          
    401390        [lines sortUsingFunction:cmp_line context:nil]; 
    402391        [lines getObjects:slines]; 
    403         //NSLog(@"%@",lines); 
     392        //NSLog(@"pre - %@",lines); 
    404393        for (int i=0;i < num;i++) { 
    405394                times[i*2]   = slines[i]->begin_time; 
     
    432421                if (finishedOutput && startedOutput) { 
    433422                        [accum deleteCharactersInRange:NSMakeRange([accum length] - 1, 1)]; // delete last newline 
    434                         SubLine *event = [[[SubLine alloc] initWithLine:accum start:start end:end] autorelease]; 
     423                        SubLine *event = [[SubLine alloc] initWithLine:accum start:start end:end]; 
    435424                         
    436425                        [outpackets addObject:event]; 
     
    438427        } 
    439428         
    440         //NSLog(@"%@",outpackets); 
    441  
    442         [lines removeAllObjects]; 
    443         if (!finished) [lines addObject:slines[num-1]]; //keep the last packet in the queue 
     429//      NSLog(@"%@",outpackets); 
     430 
     431        if (finished) [lines removeAllObjects]; 
     432        else { 
     433                for (int i = 0; i < num-1; i++) { 
     434                        if (isinrange(slines[num-1]->begin_time, slines[i]->begin_time, slines[i]->end_time)) break; 
     435                        [lines removeObject:slines[i]]; 
     436                } 
     437        } 
     438//      NSLog(@"post - %@",lines); 
    444439} 
    445440 
    446441-(SubLine*)getSerializedPacket 
    447442{ 
    448         if ([outpackets count] == 0) [self refill]; 
    449         if ([outpackets count] == 0) return nil; 
     443        if ([outpackets count] == 0)  { 
     444                [self refill]; 
     445                if ([outpackets count] == 0)  
     446                        return nil; 
     447        } 
    450448         
    451449        SubLine *sl = [outpackets objectAtIndex:0]; 
    452450        [outpackets removeObjectAtIndex:0]; 
    453451         
     452        [sl autorelease]; 
    454453        return sl; 
    455454} 
     
    458457{ 
    459458        finished = f; 
     459} 
     460 
     461-(BOOL)isEmpty 
     462{ 
     463        return [lines count] == 0 && [outpackets count] == 0; 
     464} 
     465 
     466-(NSString*)description 
     467{ 
     468        return [NSString stringWithFormat:@"i: %d o: %d finished inputting: %d",[lines count],[outpackets count],finished]; 
    460469} 
    461470@end 
     
    484493} 
    485494@end 
     495 
     496CXXSubtitleSerializer::CXXSubtitleSerializer() 
     497{ 
     498        priv = [[SubtitleSerializer alloc] init]; 
     499} 
     500 
     501CXXSubtitleSerializer::~CXXSubtitleSerializer() 
     502{ 
     503        if (priv) {[(SubtitleSerializer*)priv release]; priv = NULL;} 
     504} 
     505 
     506void CXXSubtitleSerializer::pushLine(const char *line, size_t size, unsigned start, unsigned end) 
     507{ 
     508        NSString *str = [[NSString alloc] initWithBytes:line length:size encoding:NSUTF8StringEncoding]; 
     509        NSString *strn = [str stringByAppendingString:@"\n"]; 
     510        [str release]; 
     511         
     512        SubLine *sl = [[SubLine alloc] initWithLine:strn start:start end:end]; 
     513         
     514        [sl autorelease]; 
     515         
     516        [(SubtitleSerializer*)priv addLine:sl]; 
     517} 
     518 
     519 
     520void CXXSubtitleSerializer::setFinished() 
     521{ 
     522        [(SubtitleSerializer*)priv setFinished:YES]; 
     523} 
     524 
     525const char *CXXSubtitleSerializer::popPacket(size_t *size, unsigned *start, unsigned *end) 
     526{ 
     527        SubLine *sl = [(SubtitleSerializer*)priv getSerializedPacket]; 
     528        if (!sl) return NULL; 
     529        const char *u = [sl->line UTF8String]; 
     530        *start = sl->begin_time; 
     531        *end   = sl->end_time; 
     532         
     533        *size = strlen(u); 
     534        return u; 
     535} 
     536 
     537void CXXSubtitleSerializer::release() 
     538{ 
     539        SubtitleSerializer *s = (SubtitleSerializer*)priv; 
     540        int r = [s retainCount]; 
     541        [s release]; 
     542         
     543        if (r == 1) {priv = nil; delete this;} 
     544} 
     545 
     546void CXXSubtitleSerializer::retain() 
     547{ 
     548        [(SubtitleSerializer*)priv retain]; 
     549} 
     550 
     551bool CXXSubtitleSerializer::empty() 
     552{ 
     553        return [(SubtitleSerializer*)priv isEmpty]; 
     554}