Changeset 6d95c7823c9f661571671f149185e2c6f5994b21
- Timestamp:
- 13/01/08 18:17:33
(11 months ago)
- Author:
- Pierre d'Herbemont <pdherbemont@videolan.org>
- git-committer:
- Pierre d'Herbemont <pdherbemont@videolan.org> 1200244653 +0000
- git-parent:
[d372e0d833d9167304d706a27c2716e34234c6c0]
- git-author:
- Pierre d'Herbemont <pdherbemont@videolan.org> 1200244653 +0000
- Message:
MacOSX/Framework: Support streamin media list.
-
Files:
-
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
| r3d83d9c |
r6d95c78 |
|
| 79 | 79 | const char * lib_vlc_params[] = { |
|---|
| 80 | 80 | "-I", "dummy", "--vout=opengllayer", |
|---|
| 81 | | "--no-video-title-show", "--no-sout-keep", "-vvv", "--encoder=ffmpeg" |
|---|
| | 81 | "--no-video-title-show", "--no-sout-keep", "-vvv" |
|---|
| 82 | 82 | //, "--control=motion", "--motion-use-rotate", "--video-filter=rotate" |
|---|
| 83 | 83 | }; |
|---|
| r90f36ed |
r6d95c78 |
|
| 91 | 91 | else if( event->type == libvlc_MediaInstanceReachedEnd ) |
|---|
| 92 | 92 | newState = VLCMediaPlayerStateStopped; |
|---|
| | 93 | else if( event->type == libvlc_MediaInstanceEncounteredError ) |
|---|
| | 94 | newState = VLCMediaPlayerStateError; |
|---|
| 93 | 95 | else |
|---|
| 94 | 96 | { |
|---|
| … | … | |
| 417 | 419 | - (void)setMedia:(VLCMedia *)value |
|---|
| 418 | 420 | { |
|---|
| 419 | | // We only know how to play media files...not media resources with subitems |
|---|
| 420 | | if (media != value && [media subitems] == nil) |
|---|
| | 421 | if (media != value) |
|---|
| 421 | 422 | { |
|---|
| 422 | 423 | if (media && [media compare:value] == NSOrderedSame) |
|---|
| … | … | |
| 481 | 482 | - (void)stop |
|---|
| 482 | 483 | { |
|---|
| 483 | | if( [NSThread isMainThread] ) |
|---|
| | 484 | if( 0 && [NSThread isMainThread] ) |
|---|
| 484 | 485 | { |
|---|
| 485 | 486 | /* Hack because we create a dead lock here, when the vout is stopped |
|---|
| … | … | |
| 493 | 494 | // Return if there is no media available or if the system is not in play status |
|---|
| 494 | 495 | // or pause status. |
|---|
| 495 | | if (!media || (![self isPlaying] && [self state] != VLCMediaPlayerStatePaused)) |
|---|
| | 496 | if (!media) |
|---|
| 496 | 497 | return; |
|---|
| 497 | 498 | |
|---|
| 498 | | // The following is not implemented in the core, should I fix it or just |
|---|
| 499 | | // compensate? |
|---|
| 500 | | // libvlc_exception_t ex; |
|---|
| 501 | | // libvlc_exception_init( &ex ); |
|---|
| 502 | | // libvlc_media_instance_stop((libvlc_media_instance_t *)instance, &ex); |
|---|
| 503 | | // catch_exception( &ex ); |
|---|
| 504 | | |
|---|
| 505 | | // Pause and reposition to the begining of the stream. |
|---|
| 506 | | [self pause]; |
|---|
| 507 | | [self setTime:0]; |
|---|
| 508 | | // TODO: Should we pause this or destroy the media instance so that it appears as being "stopped"? |
|---|
| | 499 | libvlc_exception_t ex; |
|---|
| | 500 | libvlc_exception_init( &ex ); |
|---|
| | 501 | libvlc_media_instance_stop((libvlc_media_instance_t *)instance, &ex); |
|---|
| | 502 | catch_exception( &ex ); |
|---|
| 509 | 503 | } |
|---|
| 510 | 504 | |
|---|
| r3d83d9c |
r6d95c78 |
|
| 16 | 16 | if( self = [super init] ) |
|---|
| 17 | 17 | { |
|---|
| 18 | | options = [NSMutableDictionary dictionaryWithDictionary:dictionary]; |
|---|
| | 18 | options = [[NSMutableDictionary dictionaryWithDictionary:dictionary] retain]; |
|---|
| 19 | 19 | } |
|---|
| 20 | 20 | return self; |
|---|
| … | … | |
| 52 | 52 | return [self streamOutputWithOptionDictionary:[NSDictionary dictionaryWithObjectsAndKeys: |
|---|
| 53 | 53 | [NSDictionary dictionaryWithObjectsAndKeys: |
|---|
| 54 | | @"x264", @"videoCodec", |
|---|
| 55 | | @"768", @"videoBitrate", |
|---|
| | 54 | @"mp4v", @"videoCodec", |
|---|
| | 55 | @"1024", @"videoBitrate", |
|---|
| 56 | 56 | @"mp4a", @"audioCodec", |
|---|
| 57 | | @"128", @"audioBitrate", |
|---|
| | 57 | @"192", @"audioBitrate", |
|---|
| 58 | 58 | @"2", @"channels", |
|---|
| 59 | 59 | @"320", @"width", |
|---|
| … | … | |
| 64 | 64 | [NSDictionary dictionaryWithObjectsAndKeys: |
|---|
| 65 | 65 | @"mp4", @"muxer", |
|---|
| | 66 | @"file", @"access", |
|---|
| | 67 | [filePath copy], @"destination", nil |
|---|
| | 68 | ], @"outputOptions", |
|---|
| | 69 | nil |
|---|
| | 70 | ] |
|---|
| | 71 | ]; |
|---|
| | 72 | } |
|---|
| | 73 | |
|---|
| | 74 | + (id)mpeg4StreamOutputWithFilePath:(NSString *)filePath |
|---|
| | 75 | { |
|---|
| | 76 | return [self streamOutputWithOptionDictionary:[NSDictionary dictionaryWithObjectsAndKeys: |
|---|
| | 77 | [NSDictionary dictionaryWithObjectsAndKeys: |
|---|
| | 78 | @"mp4v", @"videoCodec", |
|---|
| | 79 | @"1024", @"videoBitrate", |
|---|
| | 80 | @"mp4a", @"audioCodec", |
|---|
| | 81 | @"192", @"audioBitrate", |
|---|
| | 82 | nil |
|---|
| | 83 | ], @"transcodingOptions", |
|---|
| | 84 | [NSDictionary dictionaryWithObjectsAndKeys: |
|---|
| | 85 | @"mp4", @"muxer", |
|---|
| | 86 | @"file", @"access", |
|---|
| | 87 | [filePath copy], @"destination", nil |
|---|
| | 88 | ], @"outputOptions", |
|---|
| | 89 | nil |
|---|
| | 90 | ] |
|---|
| | 91 | ]; |
|---|
| | 92 | } |
|---|
| | 93 | |
|---|
| | 94 | + (id)streamOutputWithFilePath:(NSString *)filePath |
|---|
| | 95 | { |
|---|
| | 96 | return [self streamOutputWithOptionDictionary:[NSDictionary dictionaryWithObjectsAndKeys: |
|---|
| | 97 | [NSDictionary dictionaryWithObjectsAndKeys: |
|---|
| | 98 | @"ps", @"muxer", |
|---|
| | 99 | @"file", @"access", |
|---|
| | 100 | [filePath copy], @"destination", nil |
|---|
| | 101 | ], @"outputOptions", |
|---|
| | 102 | nil |
|---|
| | 103 | ] |
|---|
| | 104 | ]; |
|---|
| | 105 | } |
|---|
| | 106 | |
|---|
| | 107 | + (id)mpeg2StreamOutputWithFilePath:(NSString *)filePath; |
|---|
| | 108 | { |
|---|
| | 109 | return [self streamOutputWithOptionDictionary:[NSDictionary dictionaryWithObjectsAndKeys: |
|---|
| | 110 | [NSDictionary dictionaryWithObjectsAndKeys: |
|---|
| | 111 | @"mp2v", @"videoCodec", |
|---|
| | 112 | @"1024", @"videoBitrate", |
|---|
| | 113 | @"mp2a", @"audioCodec", |
|---|
| | 114 | @"128", @"audioBitrate", |
|---|
| | 115 | @"Yes", @"audio-sync", |
|---|
| | 116 | nil |
|---|
| | 117 | ], @"transcodingOptions", |
|---|
| | 118 | [NSDictionary dictionaryWithObjectsAndKeys: |
|---|
| | 119 | @"mpeg", @"muxer", |
|---|
| 66 | 120 | @"file", @"access", |
|---|
| 67 | 121 | [filePath copy], @"destination", nil |
|---|
| … | … | |
| 91 | 145 | NSString * width = [transcodingOptions objectForKey:@"width"]; |
|---|
| 92 | 146 | NSString * audioSync = [transcodingOptions objectForKey:@"audioSync"]; |
|---|
| | 147 | NSString * videoEncoder = [transcodingOptions objectForKey:@"videoEncoder"]; |
|---|
| | 148 | if( videoEncoder ) [subOptions addObject:[NSString stringWithFormat:@"venc=%@", videoEncoder]]; |
|---|
| 93 | 149 | if( videoCodec ) [subOptions addObject:[NSString stringWithFormat:@"vcodec=%@", videoCodec]]; |
|---|
| 94 | 150 | if( videoBitrate ) [subOptions addObject:[NSString stringWithFormat:@"vb=%@", videoBitrate]]; |
|---|
| … | … | |
| 111 | 167 | NSString * url = [outputOptions objectForKey:@"url"]; |
|---|
| 112 | 168 | NSString * access = [outputOptions objectForKey:@"access"]; |
|---|
| 113 | | if( muxer ) [subOptions addObject:[NSString stringWithFormat:@"muxer=%@", muxer]]; |
|---|
| | 169 | if( muxer ) [subOptions addObject:[NSString stringWithFormat:@"mux=%@", muxer]]; |
|---|
| 114 | 170 | if( destination ) [subOptions addObject:[NSString stringWithFormat:@"dst=\"%@\"", [destination stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]]]; |
|---|
| 115 | 171 | if( url ) [subOptions addObject:[NSString stringWithFormat:@"url=\"%@\"", [url stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]]]; |
|---|
| r3d83d9c |
r6d95c78 |
|
| 10 | 10 | #import "VLCLibVLCBridging.h" |
|---|
| 11 | 11 | |
|---|
| | 12 | @interface VLCStreamSession () |
|---|
| | 13 | @property (readwrite) BOOL isComplete; |
|---|
| | 14 | @end |
|---|
| | 15 | |
|---|
| 12 | 16 | @implementation VLCStreamSession |
|---|
| 13 | 17 | @synthesize media=originalMedia; |
|---|
| 14 | 18 | @synthesize streamOutput; |
|---|
| | 19 | @synthesize isComplete; |
|---|
| | 20 | |
|---|
| | 21 | - (id)init |
|---|
| | 22 | { |
|---|
| | 23 | if( self = [super init] ) |
|---|
| | 24 | { |
|---|
| | 25 | reattemptedConnections = 0; |
|---|
| | 26 | [self addObserver:self forKeyPath:@"state" options:NSKeyValueObservingOptionNew context:nil]; |
|---|
| | 27 | self.isComplete = NO; |
|---|
| | 28 | } |
|---|
| | 29 | return self; |
|---|
| | 30 | } |
|---|
| | 31 | |
|---|
| | 32 | - (void)dealloc |
|---|
| | 33 | { |
|---|
| | 34 | [self removeObserver:self forKeyPath:@"state"]; |
|---|
| | 35 | [super dealloc]; |
|---|
| | 36 | } |
|---|
| 15 | 37 | |
|---|
| 16 | 38 | + (id)streamSession |
|---|
| … | … | |
| 22 | 44 | - (void)startStreaming; |
|---|
| 23 | 45 | { |
|---|
| | 46 | self.isComplete = NO; |
|---|
| 24 | 47 | [self play]; |
|---|
| 25 | 48 | } |
|---|
| … | … | |
| 29 | 52 | NSString * libvlcArgs; |
|---|
| 30 | 53 | if( self.drawable ) |
|---|
| | 54 | libvlcArgs = [NSString stringWithFormat:@"duplicate{dst=display,dst=\"%@\"}",[streamOutput representedLibVLCOptions]]; |
|---|
| | 55 | else |
|---|
| | 56 | libvlcArgs = [streamOutput representedLibVLCOptions]; |
|---|
| | 57 | |
|---|
| | 58 | if( libvlcArgs ) |
|---|
| 31 | 59 | { |
|---|
| 32 | | libvlcArgs = [NSString stringWithFormat:@"duplicate{dst=display,dst=\"%@\"}",[streamOutput representedLibVLCOptions]]; |
|---|
| | 60 | [super setMedia: [VLCMedia mediaWithMedia:originalMedia andLibVLCOptions: |
|---|
| | 61 | [NSDictionary dictionaryWithObject: libvlcArgs forKey: @"sout"]]]; |
|---|
| 33 | 62 | } |
|---|
| 34 | 63 | else |
|---|
| 35 | 64 | { |
|---|
| 36 | | libvlcArgs = [streamOutput representedLibVLCOptions]; |
|---|
| | 65 | [super setMedia: self.media]; |
|---|
| 37 | 66 | } |
|---|
| 38 | | [super setMedia: [VLCMedia mediaWithMedia:originalMedia andLibVLCOptions: |
|---|
| 39 | | [NSDictionary dictionaryWithObject: libvlcArgs |
|---|
| 40 | | forKey: @"sout"]]]; |
|---|
| 41 | 67 | [super play]; |
|---|
| 42 | 68 | } |
|---|
| … | … | |
| 57 | 83 | } |
|---|
| 58 | 84 | |
|---|
| 59 | | + (NSSet *)keyPathsForValuesAffectingIsComplete |
|---|
| | 85 | + (NSSet *)keyPathsForValuesAffectingEncounteredError |
|---|
| 60 | 86 | { |
|---|
| 61 | | return [NSSet setWithObjects:@"playing", @"state", @"position", nil]; |
|---|
| | 87 | return [NSSet setWithObjects:@"state", nil]; |
|---|
| 62 | 88 | } |
|---|
| 63 | 89 | |
|---|
| 64 | | - (BOOL)isComplete |
|---|
| | 90 | - (BOOL)encounteredError; |
|---|
| 65 | 91 | { |
|---|
| 66 | | return ([self position] == 1.0 || [self state] == VLCMediaPlayerStateEnded || ([self state] == VLCMediaPlayerStateStopped && self.media)); |
|---|
| | 92 | return ([self state] == VLCMediaPlayerStateError); |
|---|
| 67 | 93 | } |
|---|
| | 94 | |
|---|
| | 95 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context |
|---|
| | 96 | { |
|---|
| | 97 | if([keyPath isEqualToString:@"state"]) |
|---|
| | 98 | { |
|---|
| | 99 | if( (([self position] == 1.0 || [self state] == VLCMediaPlayerStateEnded || ([self state] == VLCMediaPlayerStateStopped && self.media)) || |
|---|
| | 100 | [self encounteredError] ) && ![super.media subitems] ) |
|---|
| | 101 | { |
|---|
| | 102 | self.isComplete = YES; |
|---|
| | 103 | return; |
|---|
| | 104 | } |
|---|
| | 105 | if( reattemptedConnections > 4 ) |
|---|
| | 106 | return; |
|---|
| | 107 | |
|---|
| | 108 | /* Our media has in fact gained subitems, let's change our playing media */ |
|---|
| | 109 | if( [[super.media subitems] count] > 0 ) |
|---|
| | 110 | { |
|---|
| | 111 | [self stop]; |
|---|
| | 112 | self.media = [[super.media subitems] mediaAtIndex:0]; |
|---|
| | 113 | [self play]; |
|---|
| | 114 | reattemptedConnections++; |
|---|
| | 115 | } |
|---|
| | 116 | return; |
|---|
| | 117 | } |
|---|
| | 118 | [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; |
|---|
| | 119 | } |
|---|
| | 120 | |
|---|
| 68 | 121 | @end |
|---|