Browse Source

MacOSX/Framework: Support streamin media list.

Pierre d'Herbemont 17 years ago
parent
commit
fb2de8afb1
4 changed files with 133 additions and 30 deletions
  1. 1 1
      Sources/VLCLibrary.m
  2. 9 15
      Sources/VLCMediaPlayer.m
  3. 61 5
      Sources/VLCStreamOutput.m
  4. 62 9
      Sources/VLCStreamSession.m

+ 1 - 1
Sources/VLCLibrary.m

@@ -78,7 +78,7 @@ static void * DestroySharedLibraryAtExit( void )
         
         
         const char * lib_vlc_params[] = { 
         const char * lib_vlc_params[] = { 
             "-I", "dummy", "--vout=opengllayer", 
             "-I", "dummy", "--vout=opengllayer", 
-            "--no-video-title-show", "--no-sout-keep", "-vvv", "--encoder=ffmpeg"
+            "--no-video-title-show", "--no-sout-keep", "-vvv"
             //, "--control=motion", "--motion-use-rotate", "--video-filter=rotate"
             //, "--control=motion", "--motion-use-rotate", "--video-filter=rotate"
         };
         };
         
         

+ 9 - 15
Sources/VLCMediaPlayer.m

@@ -90,6 +90,8 @@ static void HandleMediaInstanceStateChanged(const libvlc_event_t * event, void *
         newState = VLCMediaPlayerStatePaused;
         newState = VLCMediaPlayerStatePaused;
     else if( event->type == libvlc_MediaInstanceReachedEnd )
     else if( event->type == libvlc_MediaInstanceReachedEnd )
         newState = VLCMediaPlayerStateStopped;
         newState = VLCMediaPlayerStateStopped;
+    else if( event->type == libvlc_MediaInstanceEncounteredError )
+        newState = VLCMediaPlayerStateError;
     else
     else
     {
     {
         NSLog(@"%s: Unknown event", __FUNCTION__);
         NSLog(@"%s: Unknown event", __FUNCTION__);
@@ -416,8 +418,7 @@ static void HandleMediaInstanceStateChanged(const libvlc_event_t * event, void *
 
 
 - (void)setMedia:(VLCMedia *)value
 - (void)setMedia:(VLCMedia *)value
 {
 {
-    // We only know how to play media files...not media resources with subitems
-    if (media != value && [media subitems] == nil)
+    if (media != value)
     {
     {
         if (media && [media compare:value] == NSOrderedSame)
         if (media && [media compare:value] == NSOrderedSame)
             return;
             return;
@@ -480,7 +481,7 @@ static void HandleMediaInstanceStateChanged(const libvlc_event_t * event, void *
 
 
 - (void)stop
 - (void)stop
 {
 {
-    if( [NSThread isMainThread] )
+    if( 0 && [NSThread isMainThread] )
     {
     {
         /* Hack because we create a dead lock here, when the vout is stopped
         /* Hack because we create a dead lock here, when the vout is stopped
          * and tries to recontact us on the main thread */
          * and tries to recontact us on the main thread */
@@ -492,20 +493,13 @@ static void HandleMediaInstanceStateChanged(const libvlc_event_t * event, void *
 
 
     // Return if there is no media available or if the system is not in play status 
     // Return if there is no media available or if the system is not in play status 
     // or pause status.
     // or pause status.
-    if (!media || (![self isPlaying] && [self state] != VLCMediaPlayerStatePaused))
+    if (!media)
         return;
         return;
     
     
-    // The following is not implemented in the core, should I fix it or just
-    // compensate?
-    //    libvlc_exception_t ex;
-    //    libvlc_exception_init( &ex );
-    //    libvlc_media_instance_stop((libvlc_media_instance_t *)instance, &ex);
-    //    catch_exception( &ex );
-    
-    // Pause and reposition to the begining of the stream.
-    [self pause];
-    [self setTime:0];
-    // TODO: Should we pause this or destroy the media instance so that it appears as being "stopped"?
+    libvlc_exception_t ex;
+    libvlc_exception_init( &ex );
+    libvlc_media_instance_stop((libvlc_media_instance_t *)instance, &ex);
+    catch_exception( &ex );
 }
 }
 
 
 - (void)fastForward
 - (void)fastForward

+ 61 - 5
Sources/VLCStreamOutput.m

@@ -15,7 +15,7 @@
 {
 {
     if( self = [super init] )
     if( self = [super init] )
     {
     {
-        options = [NSMutableDictionary dictionaryWithDictionary:dictionary];
+        options = [[NSMutableDictionary dictionaryWithDictionary:dictionary] retain];
     }
     }
     return self;
     return self;
 }
 }
@@ -51,10 +51,10 @@
 {
 {
     return [self streamOutputWithOptionDictionary:[NSDictionary dictionaryWithObjectsAndKeys:
     return [self streamOutputWithOptionDictionary:[NSDictionary dictionaryWithObjectsAndKeys:
                                             [NSDictionary dictionaryWithObjectsAndKeys:
                                             [NSDictionary dictionaryWithObjectsAndKeys:
-                                                @"x264", @"videoCodec",
-                                                @"768",  @"videoBitrate",
+                                                @"mp4v", @"videoCodec",
+                                                @"1024",  @"videoBitrate",
                                                 @"mp4a", @"audioCodec",
                                                 @"mp4a", @"audioCodec",
-                                                @"128", @"audioBitrate",
+                                                @"192", @"audioBitrate",
                                                 @"2",   @"channels",
                                                 @"2",   @"channels",
                                                 @"320", @"width",
                                                 @"320", @"width",
                                                 @"240", @"canvasHeight",
                                                 @"240", @"canvasHeight",
@@ -70,6 +70,60 @@
                                             ]
                                             ]
                                         ];
                                         ];
 }
 }
+
++ (id)mpeg4StreamOutputWithFilePath:(NSString *)filePath
+{
+    return [self streamOutputWithOptionDictionary:[NSDictionary dictionaryWithObjectsAndKeys:
+                                            [NSDictionary dictionaryWithObjectsAndKeys:
+                                                @"mp4v", @"videoCodec",
+                                                @"1024",  @"videoBitrate",
+                                                @"mp4a", @"audioCodec",
+                                                @"192", @"audioBitrate",
+                                                nil
+                                            ], @"transcodingOptions",
+                                            [NSDictionary dictionaryWithObjectsAndKeys:
+                                                @"mp4", @"muxer",
+                                                @"file", @"access",
+                                                [filePath copy], @"destination", nil
+                                            ], @"outputOptions",
+                                            nil
+                                            ]
+                                        ];
+}
+
++ (id)streamOutputWithFilePath:(NSString *)filePath
+{
+    return [self streamOutputWithOptionDictionary:[NSDictionary dictionaryWithObjectsAndKeys:
+                                            [NSDictionary dictionaryWithObjectsAndKeys:
+                                                @"ps", @"muxer",
+                                                @"file", @"access",
+                                                [filePath copy], @"destination", nil
+                                            ], @"outputOptions",
+                                            nil
+                                            ]
+                                        ];
+}
+
++ (id)mpeg2StreamOutputWithFilePath:(NSString *)filePath;
+{
+    return [self streamOutputWithOptionDictionary:[NSDictionary dictionaryWithObjectsAndKeys:
+                                            [NSDictionary dictionaryWithObjectsAndKeys:
+                                                @"mp2v", @"videoCodec",
+                                                @"1024", @"videoBitrate",
+                                                @"mp2a",   @"audioCodec",
+                                                @"128",   @"audioBitrate",
+                                                @"Yes",   @"audio-sync",
+                                                nil
+                                            ], @"transcodingOptions",
+                                            [NSDictionary dictionaryWithObjectsAndKeys:
+                                                @"mpeg", @"muxer",
+                                                @"file", @"access",
+                                                [filePath copy], @"destination", nil
+                                            ], @"outputOptions",
+                                            nil
+                                            ]
+                                        ];
+}
 @end
 @end
 
 
 @implementation VLCStreamOutput (LibVLCBridge)
 @implementation VLCStreamOutput (LibVLCBridge)
@@ -90,6 +144,8 @@
         NSString * canvasHeight = [transcodingOptions objectForKey:@"canvasHeight"];
         NSString * canvasHeight = [transcodingOptions objectForKey:@"canvasHeight"];
         NSString * width = [transcodingOptions objectForKey:@"width"];
         NSString * width = [transcodingOptions objectForKey:@"width"];
         NSString * audioSync = [transcodingOptions objectForKey:@"audioSync"];
         NSString * audioSync = [transcodingOptions objectForKey:@"audioSync"];
+        NSString * videoEncoder = [transcodingOptions objectForKey:@"videoEncoder"];
+        if( videoEncoder )   [subOptions addObject:[NSString stringWithFormat:@"venc=%@", videoEncoder]];
         if( videoCodec )   [subOptions addObject:[NSString stringWithFormat:@"vcodec=%@", videoCodec]];
         if( videoCodec )   [subOptions addObject:[NSString stringWithFormat:@"vcodec=%@", videoCodec]];
         if( videoBitrate ) [subOptions addObject:[NSString stringWithFormat:@"vb=%@", videoBitrate]];
         if( videoBitrate ) [subOptions addObject:[NSString stringWithFormat:@"vb=%@", videoBitrate]];
         if( width ) [subOptions addObject:[NSString stringWithFormat:@"width=%@", width]];
         if( width ) [subOptions addObject:[NSString stringWithFormat:@"width=%@", width]];
@@ -110,7 +166,7 @@
         NSString * destination = [outputOptions objectForKey:@"destination"];
         NSString * destination = [outputOptions objectForKey:@"destination"];
         NSString * url = [outputOptions objectForKey:@"url"];
         NSString * url = [outputOptions objectForKey:@"url"];
         NSString * access = [outputOptions objectForKey:@"access"];
         NSString * access = [outputOptions objectForKey:@"access"];
-        if( muxer )       [subOptions addObject:[NSString stringWithFormat:@"muxer=%@", muxer]];
+        if( muxer )       [subOptions addObject:[NSString stringWithFormat:@"mux=%@", muxer]];
         if( destination ) [subOptions addObject:[NSString stringWithFormat:@"dst=\"%@\"", [destination stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]]];
         if( destination ) [subOptions addObject:[NSString stringWithFormat:@"dst=\"%@\"", [destination stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]]];
         if( url ) [subOptions addObject:[NSString stringWithFormat:@"url=\"%@\"", [url stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]]];
         if( url ) [subOptions addObject:[NSString stringWithFormat:@"url=\"%@\"", [url stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]]];
         if( access )      [subOptions addObject:[NSString stringWithFormat:@"access=%@", access]];
         if( access )      [subOptions addObject:[NSString stringWithFormat:@"access=%@", access]];

+ 62 - 9
Sources/VLCStreamSession.m

@@ -9,9 +9,31 @@
 #import "VLCStreamSession.h"
 #import "VLCStreamSession.h"
 #import "VLCLibVLCBridging.h"
 #import "VLCLibVLCBridging.h"
 
 
+@interface VLCStreamSession ()
+@property (readwrite) BOOL isComplete;
+@end
+
 @implementation VLCStreamSession
 @implementation VLCStreamSession
 @synthesize media=originalMedia;
 @synthesize media=originalMedia;
 @synthesize streamOutput;
 @synthesize streamOutput;
+@synthesize isComplete;
+
+- (id)init
+{
+    if( self = [super init] )
+    {
+        reattemptedConnections = 0;
+        [self addObserver:self forKeyPath:@"state" options:NSKeyValueObservingOptionNew context:nil];
+        self.isComplete = NO;
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    [self removeObserver:self forKeyPath:@"state"];
+    [super dealloc];
+}
 
 
 + (id)streamSession
 + (id)streamSession
 {
 {
@@ -21,6 +43,7 @@
 
 
 - (void)startStreaming;
 - (void)startStreaming;
 {
 {
+    self.isComplete = NO;
     [self play];
     [self play];
 }
 }
 
 
@@ -28,16 +51,19 @@
 {
 {
     NSString * libvlcArgs;
     NSString * libvlcArgs;
     if( self.drawable )
     if( self.drawable )
-    {
         libvlcArgs = [NSString stringWithFormat:@"duplicate{dst=display,dst=\"%@\"}",[streamOutput representedLibVLCOptions]];
         libvlcArgs = [NSString stringWithFormat:@"duplicate{dst=display,dst=\"%@\"}",[streamOutput representedLibVLCOptions]];
+    else
+        libvlcArgs = [streamOutput representedLibVLCOptions];
+
+    if( libvlcArgs )
+    {
+        [super setMedia: [VLCMedia mediaWithMedia:originalMedia andLibVLCOptions:
+                                [NSDictionary dictionaryWithObject: libvlcArgs forKey: @"sout"]]];
     }
     }
     else
     else
     {
     {
-        libvlcArgs = [streamOutput representedLibVLCOptions];
+        [super setMedia: self.media];
     }
     }
-    [super setMedia: [VLCMedia mediaWithMedia:originalMedia andLibVLCOptions:
-                            [NSDictionary dictionaryWithObject: libvlcArgs
-                                                        forKey: @"sout"]]];
     [super play];
     [super play];
 }
 }
 
 
@@ -56,13 +82,40 @@
         return @"Converting...";
         return @"Converting...";
 }
 }
 
 
-+ (NSSet *)keyPathsForValuesAffectingIsComplete
++ (NSSet *)keyPathsForValuesAffectingEncounteredError
 {
 {
-    return [NSSet setWithObjects:@"playing", @"state", @"position", nil];
+    return [NSSet setWithObjects:@"state", nil];
 }
 }
 
 
-- (BOOL)isComplete
+- (BOOL)encounteredError;
 {
 {
-    return ([self position] == 1.0 || [self state] == VLCMediaPlayerStateEnded || ([self state] == VLCMediaPlayerStateStopped && self.media));
+    return ([self state] == VLCMediaPlayerStateError);
 }
 }
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
+{
+    if([keyPath isEqualToString:@"state"])
+    {
+        if( (([self position] == 1.0 || [self state] == VLCMediaPlayerStateEnded || ([self state] == VLCMediaPlayerStateStopped && self.media)) ||
+            [self encounteredError] ) && ![super.media subitems] )
+        {
+            self.isComplete = YES;
+            return;
+        }
+        if( reattemptedConnections > 4 )
+            return;
+
+        /* Our media has in fact gained subitems, let's change our playing media */
+        if( [[super.media subitems] count] > 0 )
+        {
+            [self stop];
+            self.media = [[super.media subitems] mediaAtIndex:0];
+            [self play];
+            reattemptedConnections++;
+        }
+        return;
+    }
+    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
+}
+
 @end
 @end