#import "VideoViewController.h" #import #import @interface VideoViewController () { GstPlayer *player; int media_width; /* Width of the clip */ int media_height; /* height ofthe clip */ Boolean dragging_slider; /* Whether the time slider is being dragged or not */ Boolean is_local_media; /* Whether this clip is stored locally or is being streamed */ Boolean is_playing_desired; /* Whether the user asked to go to PLAYING */ } @end @implementation VideoViewController @synthesize uri; /* * Private methods */ /* The text widget acts as an slave for the seek bar, so it reflects what the seek bar shows, whether * it is an actual pipeline position or the position the user is currently dragging to. */ - (void) updateTimeWidget { NSInteger position = time_slider.value / 1000; NSInteger duration = time_slider.maximumValue / 1000; NSString *position_txt = @" -- "; NSString *duration_txt = @" -- "; if (duration > 0) { NSUInteger hours = duration / (60 * 60); NSUInteger minutes = (duration / 60) % 60; NSUInteger seconds = duration % 60; duration_txt = [NSString stringWithFormat:@"%02u:%02u:%02u", hours, minutes, seconds]; } if (position > 0) { NSUInteger hours = position / (60 * 60); NSUInteger minutes = (position / 60) % 60; NSUInteger seconds = position % 60; position_txt = [NSString stringWithFormat:@"%02u:%02u:%02u", hours, minutes, seconds]; } NSString *text = [NSString stringWithFormat:@"%@ / %@", position_txt, duration_txt]; time_label.text = text; } /* * Methods from UIViewController */ - (void)viewDidLoad { [super viewDidLoad]; /* As soon as the GStreamer backend knows the real values, these ones will be replaced */ media_width = 320; media_height = 240; player = gst_player_new(); g_object_set (player, "window-handle", video_view, NULL); g_object_set (player, "uri", [uri UTF8String], NULL); gst_debug_set_threshold_for_name("gst-player", GST_LEVEL_TRACE); g_signal_connect (player, "position-updated", G_CALLBACK (position_updated), (__bridge gpointer) self); g_signal_connect (player, "duration-changed", G_CALLBACK (duration_changed), (__bridge gpointer) self); g_signal_connect (player, "video-dimensions-changed", G_CALLBACK (video_dimensions_changed), (__bridge gpointer) self); is_local_media = [uri hasPrefix:@"file://"]; is_playing_desired = NO; } - (void)viewDidDisappear:(BOOL)animated { if (player) { gst_object_unref (player); } [UIApplication sharedApplication].idleTimerDisabled = NO; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } /* Called when the Play button is pressed */ -(IBAction) play:(id)sender { gst_player_play (player); is_playing_desired = YES; [UIApplication sharedApplication].idleTimerDisabled = YES; } /* Called when the Pause button is pressed */ -(IBAction) pause:(id)sender { gst_player_pause(player); is_playing_desired = NO; [UIApplication sharedApplication].idleTimerDisabled = NO; } /* Called when the time slider position has changed, either because the user dragged it or * we programmatically changed its position. dragging_slider tells us which one happened */ - (IBAction)sliderValueChanged:(id)sender { if (!dragging_slider) return; // If this is a local file, allow scrub seeking, this is, seek as soon as the slider is moved. if (is_local_media) gst_player_seek (player, ((long)time_slider.value) * 1000000); [self updateTimeWidget]; } /* Called when the user starts to drag the time slider */ - (IBAction)sliderTouchDown:(id)sender { gst_player_pause (player); dragging_slider = YES; } /* Called when the user stops dragging the time slider */ - (IBAction)sliderTouchUp:(id)sender { dragging_slider = NO; // If this is a remote file, scrub seeking is probably not going to work smoothly enough. // Therefore, perform only the seek when the slider is released. if (!is_local_media) gst_player_seek (player, ((long)time_slider.value) * 1000000); if (is_playing_desired) gst_player_play (player); } /* Called when the size of the main view has changed, so we can * resize the sub-views in ways not allowed by storyboarding. */ - (void)viewDidLayoutSubviews { CGFloat view_width = video_container_view.bounds.size.width; CGFloat view_height = video_container_view.bounds.size.height; CGFloat correct_height = view_width * media_height / media_width; CGFloat correct_width = view_height * media_width / media_height; if (correct_height < view_height) { video_height_constraint.constant = correct_height; video_width_constraint.constant = view_width; } else { video_width_constraint.constant = correct_width; video_height_constraint.constant = view_height; } time_slider.frame = CGRectMake(time_slider.frame.origin.x, time_slider.frame.origin.y, toolbar.frame.size.width - time_slider.frame.origin.x - 8, time_slider.frame.size.height); } static void video_dimensions_changed (GstPlayer * unused, gint width, gint height, VideoViewController * self) { dispatch_async(dispatch_get_main_queue(), ^{ if (width > 0 && height > 0) { [self videoDimensionsChanged:width height:height]; } }); } -(void) videoDimensionsChanged:(NSInteger)width height:(NSInteger)height { media_width = width; media_height = height; [self viewDidLayoutSubviews]; [video_view setNeedsLayout]; [video_view layoutIfNeeded]; } static void position_updated (GstPlayer * unused, GstClockTime position, VideoViewController *self) { dispatch_async(dispatch_get_main_queue(), ^{ [self positionUpdated:(int) (position / 1000000)]; }); } -(void) positionUpdated:(NSInteger)position { /* Ignore messages from the pipeline if the time sliders is being dragged */ if (dragging_slider) return; time_slider.value = position; [self updateTimeWidget]; } static void duration_changed (GstPlayer * unused, GstClockTime duration, VideoViewController *self) { dispatch_async(dispatch_get_main_queue(), ^{ [self durationChanged:(int) (duration / 1000000)]; }); } -(void) durationChanged:(NSInteger)duration { time_slider.maximumValue = duration; [self updateTimeWidget]; } @end