From 4ae44f9e1c1343b5f720cab24bb6f8bca9f01bd0 Mon Sep 17 00:00:00 2001 From: Xavi Artigas Date: Tue, 14 May 2013 17:11:05 +0200 Subject: [PATCH] Initial iOS Tutorial 4, already working. No seek bar yet. iPhone storyboard missing. External files can be played if they are copied into the application through iTunes file sharing. --- .../project.pbxproj | 20 ++-- .../xcode iOS/Tutorial 4/GStreamerBackend.h | 8 ++ .../xcode iOS/Tutorial 4/GStreamerBackend.m | 30 ++--- .../Tutorial 4/LibraryViewController.h | 11 ++ .../Tutorial 4/LibraryViewController.m | 106 ++++++++++++++++++ .../Tutorial 4/Tutorial 4-Info.plist | 2 + ...ViewController.h => VideoViewController.h} | 4 +- ...ViewController.m => VideoViewController.m} | 17 ++- .../en.lproj/MainStoryboard_iPad.storyboard | 87 ++++++++++++-- .../xcode iOS/Tutorial 4/gst_ios_init.h | 10 +- 10 files changed, 259 insertions(+), 36 deletions(-) create mode 100644 gst-sdk/tutorials/xcode iOS/Tutorial 4/LibraryViewController.h create mode 100644 gst-sdk/tutorials/xcode iOS/Tutorial 4/LibraryViewController.m rename gst-sdk/tutorials/xcode iOS/Tutorial 4/{ViewController.h => VideoViewController.h} (81%) rename gst-sdk/tutorials/xcode iOS/Tutorial 4/{ViewController.m => VideoViewController.m} (87%) diff --git a/gst-sdk/tutorials/xcode iOS/GStreamer iOS Tutorials.xcodeproj/project.pbxproj b/gst-sdk/tutorials/xcode iOS/GStreamer iOS Tutorials.xcodeproj/project.pbxproj index 061137bd97..85889fe4a7 100644 --- a/gst-sdk/tutorials/xcode iOS/GStreamer iOS Tutorials.xcodeproj/project.pbxproj +++ b/gst-sdk/tutorials/xcode iOS/GStreamer iOS Tutorials.xcodeproj/project.pbxproj @@ -76,7 +76,7 @@ C6EB8597173BEE5E00C3953D /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C6EB8596173BEE5E00C3953D /* Default-568h@2x.png */; }; C6EB859A173BEE5E00C3953D /* MainStoryboard_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C6EB8598173BEE5E00C3953D /* MainStoryboard_iPhone.storyboard */; }; C6EB859D173BEE5E00C3953D /* MainStoryboard_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C6EB859B173BEE5E00C3953D /* MainStoryboard_iPad.storyboard */; }; - C6EB85A0173BEE5E00C3953D /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C6EB859F173BEE5E00C3953D /* ViewController.m */; }; + C6EB85A0173BEE5E00C3953D /* VideoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C6EB859F173BEE5E00C3953D /* VideoViewController.m */; }; C6EB85B1173BEF2600C3953D /* EaglUIVIew.m in Sources */ = {isa = PBXBuildFile; fileRef = C6EB85AB173BEF2600C3953D /* EaglUIVIew.m */; }; C6EB85B2173BEF2600C3953D /* gst_ios_init.c in Sources */ = {isa = PBXBuildFile; fileRef = C6EB85AC173BEF2600C3953D /* gst_ios_init.c */; }; C6EB85B3173BEF2600C3953D /* GStreamerBackend.m in Sources */ = {isa = PBXBuildFile; fileRef = C6EB85AF173BEF2600C3953D /* GStreamerBackend.m */; }; @@ -84,6 +84,7 @@ C6EB85BA173BEFF800C3953D /* appicon-4-iPad@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C6EB85B6173BEFF800C3953D /* appicon-4-iPad@2x.png */; }; C6EB85BB173BEFF800C3953D /* appicon-4-iPhone.png in Resources */ = {isa = PBXBuildFile; fileRef = C6EB85B7173BEFF800C3953D /* appicon-4-iPhone.png */; }; C6EB85BC173BEFF800C3953D /* appicon-4-iPhone@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C6EB85B8173BEFF800C3953D /* appicon-4-iPhone@2x.png */; }; + C6EB85C7174233B400C3953D /* LibraryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C6EB85C6174233B300C3953D /* LibraryViewController.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -173,11 +174,11 @@ C6EB8596173BEE5E00C3953D /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; C6EB8599173BEE5E00C3953D /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPhone.storyboard; sourceTree = ""; }; C6EB859C173BEE5E00C3953D /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPad.storyboard; sourceTree = ""; }; - C6EB859E173BEE5E00C3953D /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; - C6EB859F173BEE5E00C3953D /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; + C6EB859E173BEE5E00C3953D /* VideoViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VideoViewController.h; sourceTree = ""; }; + C6EB859F173BEE5E00C3953D /* VideoViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VideoViewController.m; sourceTree = ""; }; C6EB85AA173BEF2600C3953D /* EaglUIVIew.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EaglUIVIew.h; sourceTree = ""; }; C6EB85AB173BEF2600C3953D /* EaglUIVIew.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EaglUIVIew.m; sourceTree = ""; }; - C6EB85AC173BEF2600C3953D /* gst_ios_init.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gst_ios_init.c; sourceTree = ""; }; + C6EB85AC173BEF2600C3953D /* gst_ios_init.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.c; path = gst_ios_init.c; sourceTree = ""; tabWidth = 2; }; C6EB85AD173BEF2600C3953D /* gst_ios_init.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gst_ios_init.h; sourceTree = ""; }; C6EB85AE173BEF2600C3953D /* GStreamerBackend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GStreamerBackend.h; sourceTree = ""; }; C6EB85AF173BEF2600C3953D /* GStreamerBackend.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GStreamerBackend.m; sourceTree = ""; }; @@ -186,6 +187,8 @@ C6EB85B6173BEFF800C3953D /* appicon-4-iPad@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "appicon-4-iPad@2x.png"; sourceTree = ""; }; C6EB85B7173BEFF800C3953D /* appicon-4-iPhone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "appicon-4-iPhone.png"; sourceTree = ""; }; C6EB85B8173BEFF800C3953D /* appicon-4-iPhone@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "appicon-4-iPhone@2x.png"; sourceTree = ""; }; + C6EB85C5174233B200C3953D /* LibraryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LibraryViewController.h; sourceTree = ""; }; + C6EB85C6174233B300C3953D /* LibraryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LibraryViewController.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -418,8 +421,10 @@ C6EB8590173BEE5E00C3953D /* AppDelegate.m */, C6EB8598173BEE5E00C3953D /* MainStoryboard_iPhone.storyboard */, C6EB859B173BEE5E00C3953D /* MainStoryboard_iPad.storyboard */, - C6EB859E173BEE5E00C3953D /* ViewController.h */, - C6EB859F173BEE5E00C3953D /* ViewController.m */, + C6EB85C5174233B200C3953D /* LibraryViewController.h */, + C6EB85C6174233B300C3953D /* LibraryViewController.m */, + C6EB859E173BEE5E00C3953D /* VideoViewController.h */, + C6EB859F173BEE5E00C3953D /* VideoViewController.m */, C6EB8587173BEE5E00C3953D /* Supporting Files */, ); path = "Tutorial 4"; @@ -666,10 +671,11 @@ files = ( C6EB858D173BEE5E00C3953D /* main.m in Sources */, C6EB8591173BEE5E00C3953D /* AppDelegate.m in Sources */, - C6EB85A0173BEE5E00C3953D /* ViewController.m in Sources */, + C6EB85A0173BEE5E00C3953D /* VideoViewController.m in Sources */, C6EB85B1173BEF2600C3953D /* EaglUIVIew.m in Sources */, C6EB85B2173BEF2600C3953D /* gst_ios_init.c in Sources */, C6EB85B3173BEF2600C3953D /* GStreamerBackend.m in Sources */, + C6EB85C7174233B400C3953D /* LibraryViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/gst-sdk/tutorials/xcode iOS/Tutorial 4/GStreamerBackend.h b/gst-sdk/tutorials/xcode iOS/Tutorial 4/GStreamerBackend.h index a23c4cefe6..1fe4853152 100644 --- a/gst-sdk/tutorials/xcode iOS/Tutorial 4/GStreamerBackend.h +++ b/gst-sdk/tutorials/xcode iOS/Tutorial 4/GStreamerBackend.h @@ -8,10 +8,18 @@ * Pass also the UIView object that will hold the video window. */ -(id) init:(id) uiDelegate videoView:(UIView*) video_view; +/* Quit the main loop and free all resources, including the pipeline and + * the references to the ui delegate and the UIView used for rendering, so + * these objects can be deallocated. */ +-(void) deinit; + /* Set the pipeline to PLAYING */ -(void) play; /* Set the pipeline to PAUSED */ -(void) pause; +/* Set the URI to be played */ +-(void) setUri:(NSString*)uri; + @end \ No newline at end of file diff --git a/gst-sdk/tutorials/xcode iOS/Tutorial 4/GStreamerBackend.m b/gst-sdk/tutorials/xcode iOS/Tutorial 4/GStreamerBackend.m index 8adceac8be..b15ef43b0b 100644 --- a/gst-sdk/tutorials/xcode iOS/Tutorial 4/GStreamerBackend.m +++ b/gst-sdk/tutorials/xcode iOS/Tutorial 4/GStreamerBackend.m @@ -45,28 +45,28 @@ GST_DEBUG_CATEGORY_STATIC (debug_category); return self; } --(void) dealloc +-(void) deinit { - if (pipeline) { - GST_DEBUG("Setting the pipeline to NULL"); - gst_element_set_state(pipeline, GST_STATE_NULL); - gst_object_unref(pipeline); - pipeline = NULL; + if (main_loop) { + g_main_loop_quit(main_loop); } } -(void) play { - if(gst_element_set_state(pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { - [self setUIMessage:"Failed to set pipeline to playing"]; - } + gst_element_set_state(pipeline, GST_STATE_PLAYING); } -(void) pause { - if(gst_element_set_state(pipeline, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) { - [self setUIMessage:"Failed to set pipeline to paused"]; - } + gst_element_set_state(pipeline, GST_STATE_PAUSED); +} + +-(void) setUri:(NSString*)uri +{ + const char *char_uri = [uri UTF8String]; + g_object_set(pipeline, "uri", char_uri, NULL); + GST_DEBUG ("URI set to %s", char_uri); } /* @@ -140,7 +140,7 @@ static void state_changed_cb (GstBus *bus, GstMessage *msg, GStreamerBackend *se g_main_context_push_thread_default(context); /* Build pipeline */ - pipeline = gst_parse_launch("videotestsrc ! warptv ! ffmpegcolorspace ! autovideosink", &error); + pipeline = gst_parse_launch("playbin2", &error); if (error) { gchar *message = g_strdup_printf("Unable to build pipeline: %s", error->message); g_clear_error (&error); @@ -183,7 +183,11 @@ static void state_changed_cb (GstBus *bus, GstMessage *msg, GStreamerBackend *se g_main_context_unref (context); gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline); + pipeline = NULL; + ui_delegate = NULL; + ui_video_view = NULL; + return; } diff --git a/gst-sdk/tutorials/xcode iOS/Tutorial 4/LibraryViewController.h b/gst-sdk/tutorials/xcode iOS/Tutorial 4/LibraryViewController.h new file mode 100644 index 0000000000..db18bfaf2c --- /dev/null +++ b/gst-sdk/tutorials/xcode iOS/Tutorial 4/LibraryViewController.h @@ -0,0 +1,11 @@ +#import + +@interface LibraryViewController : UITableViewController +{ + NSArray *mediaEntries; + NSArray *onlineEntries; +} + +- (IBAction)refresh:(id)sender; + +@end diff --git a/gst-sdk/tutorials/xcode iOS/Tutorial 4/LibraryViewController.m b/gst-sdk/tutorials/xcode iOS/Tutorial 4/LibraryViewController.m new file mode 100644 index 0000000000..faa57eccdf --- /dev/null +++ b/gst-sdk/tutorials/xcode iOS/Tutorial 4/LibraryViewController.m @@ -0,0 +1,106 @@ +#import "LibraryViewController.h" +#import "VideoViewController.h" + +@interface LibraryViewController () + +@end + +@implementation LibraryViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; + [super setTitle:@"Library"]; + [self refreshMediaItems]; +} + +- (IBAction)refresh:(id)sender +{ + [self refreshMediaItems]; + [self.tableView reloadData]; +} + +static NSString *CellIdentifier = @"CellIdentifier"; + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 2; +} + +- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section +{ + switch (section) + { + case 0: return @"Local files (iTunes file sharing)"; + default: return @"Online files"; + } +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + switch (section) { + case 0: + return [self->mediaEntries count]; + case 1: + return [self->onlineEntries count]; + default: + return 0; + } +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + // Configure Cell + UILabel *title = (UILabel *)[cell.contentView viewWithTag:10]; + UILabel *subtitle = (UILabel *)[cell.contentView viewWithTag:11]; + + if(indexPath.section == 0) + { + subtitle.text = [NSString stringWithFormat:@"file://%@", + [self->mediaEntries objectAtIndex:indexPath.item], nil]; + } else if (indexPath.section == 1) + { + subtitle.text = [self->onlineEntries objectAtIndex:indexPath.item]; + } + + NSArray *components = [subtitle.text pathComponents]; + title.text = components.lastObject; + + return cell; +} + +- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { + return NO; +} + +- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { + return NO; +} + +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + if ([segue.identifier isEqualToString:@"playVideo"]) { + NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; + VideoViewController *destViewController = segue.destinationViewController; + UITableViewCell *cell = [[self tableView] cellForRowAtIndexPath:indexPath]; + UILabel *label = (UILabel *)[cell.contentView viewWithTag:10]; + destViewController.title = label.text; + label = (UILabel *)[cell.contentView viewWithTag:11]; + destViewController.uri = label.text; + } +} + +- (void)refreshMediaItems { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSAllDomainsMask, YES); + NSString *docsPath = [paths objectAtIndex:0]; + + NSMutableArray *entries = [[NSMutableArray alloc] init]; + for (NSString *e in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:docsPath error:nil]) + { + [entries addObject:[NSString stringWithFormat:@"%@/%@",docsPath, e]]; + } + self->mediaEntries = entries; + self->onlineEntries = [NSArray arrayWithObjects: + @"http://docs.gstreamer.com/media/sintel_trailer-368p.ogv", + @"http://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_640x360.m4v", + nil]; +} + +@end diff --git a/gst-sdk/tutorials/xcode iOS/Tutorial 4/Tutorial 4-Info.plist b/gst-sdk/tutorials/xcode iOS/Tutorial 4/Tutorial 4-Info.plist index 68ea7113ae..548df055de 100644 --- a/gst-sdk/tutorials/xcode iOS/Tutorial 4/Tutorial 4-Info.plist +++ b/gst-sdk/tutorials/xcode iOS/Tutorial 4/Tutorial 4-Info.plist @@ -37,6 +37,8 @@ 1.0 LSRequiresIPhoneOS + UIFileSharingEnabled + UIMainStoryboardFile MainStoryboard_iPhone UIMainStoryboardFile~ipad diff --git a/gst-sdk/tutorials/xcode iOS/Tutorial 4/ViewController.h b/gst-sdk/tutorials/xcode iOS/Tutorial 4/VideoViewController.h similarity index 81% rename from gst-sdk/tutorials/xcode iOS/Tutorial 4/ViewController.h rename to gst-sdk/tutorials/xcode iOS/Tutorial 4/VideoViewController.h index 677f65bc25..37064f1541 100644 --- a/gst-sdk/tutorials/xcode iOS/Tutorial 4/ViewController.h +++ b/gst-sdk/tutorials/xcode iOS/Tutorial 4/VideoViewController.h @@ -1,7 +1,7 @@ #import #import "GStreamerBackendDelegate.h" -@interface ViewController : UIViewController { +@interface VideoViewController : UIViewController { IBOutlet UILabel *message_label; IBOutlet UIBarButtonItem *play_button; IBOutlet UIBarButtonItem *pause_button; @@ -11,6 +11,8 @@ IBOutlet NSLayoutConstraint *video_height_constraint; } +@property (retain,nonatomic) NSString *uri; + -(IBAction) play:(id)sender; -(IBAction) pause:(id)sender; diff --git a/gst-sdk/tutorials/xcode iOS/Tutorial 4/ViewController.m b/gst-sdk/tutorials/xcode iOS/Tutorial 4/VideoViewController.m similarity index 87% rename from gst-sdk/tutorials/xcode iOS/Tutorial 4/ViewController.m rename to gst-sdk/tutorials/xcode iOS/Tutorial 4/VideoViewController.m index 93eae203e4..d4bc16d0d6 100644 --- a/gst-sdk/tutorials/xcode iOS/Tutorial 4/ViewController.m +++ b/gst-sdk/tutorials/xcode iOS/Tutorial 4/VideoViewController.m @@ -1,8 +1,8 @@ -#import "ViewController.h" +#import "VideoViewController.h" #import "GStreamerBackend.h" #import -@interface ViewController () { +@interface VideoViewController () { GStreamerBackend *gst_backend; int media_width; int media_height; @@ -10,7 +10,9 @@ @end -@implementation ViewController +@implementation VideoViewController + +@synthesize uri; /* * Methods from UIViewController @@ -30,6 +32,14 @@ gst_backend = [[GStreamerBackend alloc] init:self videoView:video_view]; } +- (void)viewDidDisappear:(BOOL)animated +{ + if (gst_backend) + { + [gst_backend deinit]; + } +} + - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; @@ -75,6 +85,7 @@ play_button.enabled = TRUE; pause_button.enabled = TRUE; message_label.text = @"Ready"; + [gst_backend setUri:uri]; }); } diff --git a/gst-sdk/tutorials/xcode iOS/Tutorial 4/en.lproj/MainStoryboard_iPad.storyboard b/gst-sdk/tutorials/xcode iOS/Tutorial 4/en.lproj/MainStoryboard_iPad.storyboard index 98d0b70aaf..c1b9cf238f 100644 --- a/gst-sdk/tutorials/xcode iOS/Tutorial 4/en.lproj/MainStoryboard_iPad.storyboard +++ b/gst-sdk/tutorials/xcode iOS/Tutorial 4/en.lproj/MainStoryboard_iPad.storyboard @@ -1,15 +1,30 @@ - + - + + + + + + + + + + + + + + + + - + - + @@ -71,6 +86,7 @@ + @@ -84,18 +100,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + - diff --git a/gst-sdk/tutorials/xcode iOS/Tutorial 4/gst_ios_init.h b/gst-sdk/tutorials/xcode iOS/Tutorial 4/gst_ios_init.h index 3e3406ef56..6129a94210 100644 --- a/gst-sdk/tutorials/xcode iOS/Tutorial 4/gst_ios_init.h +++ b/gst-sdk/tutorials/xcode iOS/Tutorial 4/gst_ios_init.h @@ -11,17 +11,17 @@ G_BEGIN_DECLS #define GST_IOS_PLUGINS_CORE //#define GST_IOS_PLUGINS_CAPTURE -//#define GST_IOS_PLUGINS_CODECS_RESTRICTED +#define GST_IOS_PLUGINS_CODECS_RESTRICTED //#define GST_IOS_PLUGINS_ENCODING //#define GST_IOS_PLUGINS_DVD -//#define GST_IOS_PLUGINS_CODECS_GPL -//#define GST_IOS_PLUGINS_NET_RESTRICTED +#define GST_IOS_PLUGINS_CODECS_GPL +#define GST_IOS_PLUGINS_NET_RESTRICTED #define GST_IOS_PLUGINS_SYS //#define GST_IOS_PLUGINS_VIS #define GST_IOS_PLUGINS_PLAYBACK #define GST_IOS_PLUGINS_EFFECTS -//#define GST_IOS_PLUGINS_CODECS -//#define GST_IOS_PLUGINS_NET +#define GST_IOS_PLUGINS_CODECS +#define GST_IOS_PLUGINS_NET void gst_ios_init ();