Changeset 333
- Timestamp:
- 02/08/07 02:35:51 (2 years ago)
- Files:
-
- trunk/MatroskaImport.cpp (modified) (3 diffs)
- trunk/MatroskaImport.h (modified) (4 diffs)
- trunk/MatroskaImportPrivate.cpp (modified) (10 diffs)
- trunk/SubImport.h (modified) (2 diffs)
- trunk/SubImport.mm (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/MatroskaImport.cpp
r302 r333 271 271 if (!NextLevel1Element()) 272 272 *outFlags |= movieImportResultComplete; 273 else 273 else { 274 274 *outFlags |= movieImportResultNeedIdles; 275 return noErr; 276 } 275 277 276 return noErr;277 278 } 278 279 … … 291 292 // insert the a/v tracks' samples 292 293 for (int i = 0; i < tracks.size(); i++) 293 tracks[i]. AddSamplesToTrack();294 tracks[i].FinishTrack(); 294 295 295 296 } catch (CRTError &err) { … … 336 337 *outFlags |= movieImportResultComplete; 337 338 loadState = kMovieLoadStateComplete; 339 340 for (int i = 0; i < tracks.size(); i++) 341 tracks[i].FinishTrack(); 338 342 } 339 343 trunk/MatroskaImport.h
r323 r333 29 29 #include <QuickTime/QuickTime.h> 30 30 #include "DataHandlerCallback.h" 31 #include "SubImport.h" 31 32 32 33 #include <ebml/EbmlStream.h> … … 49 50 SInt64 size; 50 51 short flags; 52 DataBuffer *buffer; 51 53 }; 52 54 … … 69 71 // added, e.g. from a previous call to AddSamplesToTrack() 70 72 void AddSamplesToTrack(); 73 74 void FinishTrack(); 71 75 72 76 UInt16 number; … … 79 83 SInt64 timecodeScale; 80 84 TimeValue64 maxLoadedTime; 85 CXXSubtitleSerializer *subtitleSerializer; 86 Handle subDataRefHandler; 81 87 82 88 private: trunk/MatroskaImportPrivate.cpp
r328 r333 463 463 } else if ((*imgDesc)->cType == kSubFormatUTF8 || (*imgDesc)->cType == kSubFormatSSA || (*imgDesc)->cType == kSubFormatASS) { 464 464 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); 467 473 if (mkvTrack.theTrack == NULL) 468 474 return GetMoviesError(); … … 471 477 mh = GetMediaHandler(mkvTrack.theMedia); 472 478 MediaSetGraphicsMode(mh, graphicsModePreBlackAlpha, NULL); 479 480 BeginMediaEdits(mkvTrack.theMedia); 473 481 } else { 474 482 Codecprintf(NULL, "MKV: Unsupported subtitle type\n"); … … 580 588 while (attachedFile && attachedFile->GetSize() > 0) { 581 589 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") { 584 593 KaxFileData & fontData = GetChild<KaxFileData>(*attachedFile); 585 594 … … 641 650 firstSample = -1; 642 651 amountToAdd = 0; 652 subtitleSerializer = new CXXSubtitleSerializer; 653 subDataRefHandler = NULL; 643 654 } 644 655 … … 670 681 firstSample = copy.firstSample; 671 682 amountToAdd = copy.amountToAdd; 683 684 subtitleSerializer = copy.subtitleSerializer; 685 subtitleSerializer->retain(); 686 687 subDataRefHandler = copy.subDataRefHandler; 672 688 } 673 689 … … 679 695 if (sampleTable) 680 696 QTSampleTableRelease(sampleTable); 697 698 if (subtitleSerializer) 699 subtitleSerializer->release(); 681 700 } 682 701 … … 729 748 newFrame.size = block.GetFrameSize(i); 730 749 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); 733 753 AddFrame(newFrame); 754 } 734 755 else 735 756 lastFrames.push_back(newFrame); 757 758 newFrame.buffer = NULL; 736 759 } 737 760 } … … 743 766 TimeValue sampleTime; 744 767 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) { 746 786 err = QTSampleTableAddSampleReferences(sampleTable, frame.offset, frame.size, frame.duration, 747 787 0, 1, frame.flags, qtSampleDesc, &sampleNum); … … 773 813 if (type == track_subtitle) { 774 814 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; 783 817 } 784 818 err = InsertMediaIntoTrack(theTrack, frame.timecode, sampleTime, frame.duration, fixed1); … … 797 831 OSStatus err = noErr; 798 832 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); 808 846 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 818 850 maxLoadedTime += amountToAdd; 819 851 firstSample = -1; 820 852 amountToAdd = 0; 821 853 } 854 855 void 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 48 48 } 49 49 -(void)addLine:(SubLine *)sline; 50 -(void)addLineWithString:(NSString*)string start:(unsigned)start end:(unsigned)end;51 50 -(void)setFinished:(BOOL)finished; 52 51 -(SubLine*)getSerializedPacket; … … 54 53 #endif 55 54 55 #ifdef __cplusplus 56 class CXXSubtitleSerializer 57 { 58 void *priv; 59 60 public: 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 }; 56 71 #endif 72 #endif trunk/SubImport.mm
r332 r333 355 355 } 356 356 357 -(void)addLineWithString:(NSString*)string start:(unsigned)start end:(unsigned)end358 {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 368 357 static int cmp_line(id a, id b, void* unused) 369 358 { … … 396 385 { 397 386 unsigned num = [lines count]; 387 if (num == 0) return; 398 388 unsigned times[num*2+1]; 399 389 SubLine *slines[num]; 400 401 390 [lines sortUsingFunction:cmp_line context:nil]; 402 391 [lines getObjects:slines]; 403 //NSLog(@" %@",lines);392 //NSLog(@"pre - %@",lines); 404 393 for (int i=0;i < num;i++) { 405 394 times[i*2] = slines[i]->begin_time; … … 432 421 if (finishedOutput && startedOutput) { 433 422 [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]; 435 424 436 425 [outpackets addObject:event]; … … 438 427 } 439 428 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); 444 439 } 445 440 446 441 -(SubLine*)getSerializedPacket 447 442 { 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 } 450 448 451 449 SubLine *sl = [outpackets objectAtIndex:0]; 452 450 [outpackets removeObjectAtIndex:0]; 453 451 452 [sl autorelease]; 454 453 return sl; 455 454 } … … 458 457 { 459 458 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]; 460 469 } 461 470 @end … … 484 493 } 485 494 @end 495 496 CXXSubtitleSerializer::CXXSubtitleSerializer() 497 { 498 priv = [[SubtitleSerializer alloc] init]; 499 } 500 501 CXXSubtitleSerializer::~CXXSubtitleSerializer() 502 { 503 if (priv) {[(SubtitleSerializer*)priv release]; priv = NULL;} 504 } 505 506 void 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 520 void CXXSubtitleSerializer::setFinished() 521 { 522 [(SubtitleSerializer*)priv setFinished:YES]; 523 } 524 525 const 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 537 void 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 546 void CXXSubtitleSerializer::retain() 547 { 548 [(SubtitleSerializer*)priv retain]; 549 } 550 551 bool CXXSubtitleSerializer::empty() 552 { 553 return [(SubtitleSerializer*)priv isEmpty]; 554 }
