1 #import "VideoViewController.h"
2 #import <gst/player/player.h>
3 #import <UIKit/UIKit.h>
5 @interface VideoViewController () {
7 int media_width; /* Width of the clip */
8 int media_height; /* height ofthe clip */
9 Boolean dragging_slider; /* Whether the time slider is being dragged or not */
10 Boolean is_local_media; /* Whether this clip is stored locally or is being streamed */
11 Boolean is_playing_desired; /* Whether the user asked to go to PLAYING */
16 @implementation VideoViewController
24 /* The text widget acts as an slave for the seek bar, so it reflects what the seek bar shows, whether
25 * it is an actual pipeline position or the position the user is currently dragging to. */
26 - (void) updateTimeWidget
28 NSInteger position = time_slider.value / 1000;
29 NSInteger duration = time_slider.maximumValue / 1000;
30 NSString *position_txt = @" -- ";
31 NSString *duration_txt = @" -- ";
34 NSUInteger hours = duration / (60 * 60);
35 NSUInteger minutes = (duration / 60) % 60;
36 NSUInteger seconds = duration % 60;
38 duration_txt = [NSString stringWithFormat:@"%02u:%02u:%02u", hours, minutes, seconds];
41 NSUInteger hours = position / (60 * 60);
42 NSUInteger minutes = (position / 60) % 60;
43 NSUInteger seconds = position % 60;
45 position_txt = [NSString stringWithFormat:@"%02u:%02u:%02u", hours, minutes, seconds];
48 NSString *text = [NSString stringWithFormat:@"%@ / %@",
49 position_txt, duration_txt];
51 time_label.text = text;
55 * Methods from UIViewController
62 /* As soon as the GStreamer backend knows the real values, these ones will be replaced */
66 player = gst_player_new (gst_player_video_overlay_video_renderer_new ((__bridge gpointer)(video_view)), NULL);
67 g_object_set (player, "uri", [uri UTF8String], NULL);
69 gst_debug_set_threshold_for_name("gst-player", GST_LEVEL_TRACE);
71 g_signal_connect (player, "position-updated", G_CALLBACK (position_updated), (__bridge gpointer) self);
72 g_signal_connect (player, "duration-changed", G_CALLBACK (duration_changed), (__bridge gpointer) self);
73 g_signal_connect (player, "video-dimensions-changed", G_CALLBACK (video_dimensions_changed), (__bridge gpointer) self);
75 is_local_media = [uri hasPrefix:@"file://"];
76 is_playing_desired = NO;
78 time_slider.value = 0;
79 time_slider.minimumValue = 0;
80 time_slider.maximumValue = 0;
83 - (void)viewDidDisappear:(BOOL)animated
87 gst_object_unref (player);
89 [UIApplication sharedApplication].idleTimerDisabled = NO;
92 - (void)didReceiveMemoryWarning
94 [super didReceiveMemoryWarning];
95 // Dispose of any resources that can be recreated.
98 /* Called when the Play button is pressed */
99 -(IBAction) play:(id)sender
101 gst_player_play (player);
102 is_playing_desired = YES;
103 [UIApplication sharedApplication].idleTimerDisabled = YES;
106 /* Called when the Pause button is pressed */
107 -(IBAction) pause:(id)sender
109 gst_player_pause(player);
110 is_playing_desired = NO;
111 [UIApplication sharedApplication].idleTimerDisabled = NO;
114 /* Called when the time slider position has changed, either because the user dragged it or
115 * we programmatically changed its position. dragging_slider tells us which one happened */
116 - (IBAction)sliderValueChanged:(id)sender {
117 if (!dragging_slider) return;
118 // If this is a local file, allow scrub seeking, this is, seek as soon as the slider is moved.
120 gst_player_seek (player, time_slider.value * 1000000);
121 [self updateTimeWidget];
124 /* Called when the user starts to drag the time slider */
125 - (IBAction)sliderTouchDown:(id)sender {
126 gst_player_pause (player);
127 dragging_slider = YES;
130 /* Called when the user stops dragging the time slider */
131 - (IBAction)sliderTouchUp:(id)sender {
132 dragging_slider = NO;
133 // If this is a remote file, scrub seeking is probably not going to work smoothly enough.
134 // Therefore, perform only the seek when the slider is released.
136 gst_player_seek (player, ((long)time_slider.value) * 1000000);
137 if (is_playing_desired)
138 gst_player_play (player);
141 /* Called when the size of the main view has changed, so we can
142 * resize the sub-views in ways not allowed by storyboarding. */
143 - (void)viewDidLayoutSubviews
145 CGFloat view_width = video_container_view.bounds.size.width;
146 CGFloat view_height = video_container_view.bounds.size.height;
148 CGFloat correct_height = view_width * media_height / media_width;
149 CGFloat correct_width = view_height * media_width / media_height;
151 if (correct_height < view_height) {
152 video_height_constraint.constant = correct_height;
153 video_width_constraint.constant = view_width;
155 video_width_constraint.constant = correct_width;
156 video_height_constraint.constant = view_height;
160 static void video_dimensions_changed (GstPlayer * unused, gint width, gint height, VideoViewController * self)
162 dispatch_async(dispatch_get_main_queue(), ^{
163 if (width > 0 && height > 0) {
164 [self videoDimensionsChanged:width height:height];
169 -(void) videoDimensionsChanged:(NSInteger)width height:(NSInteger)height
172 media_height = height;
173 [self viewDidLayoutSubviews];
174 [video_view setNeedsLayout];
175 [video_view layoutIfNeeded];
178 static void position_updated (GstPlayer * unused, GstClockTime position, VideoViewController *self)
180 dispatch_async(dispatch_get_main_queue(), ^{
181 [self positionUpdated:(int) (position / 1000000)];
185 -(void) positionUpdated:(NSInteger)position
187 /* Ignore messages from the pipeline if the time sliders is being dragged */
188 if (dragging_slider) return;
190 time_slider.value = position;
191 [self updateTimeWidget];
194 static void duration_changed (GstPlayer * unused, GstClockTime duration, VideoViewController *self)
196 dispatch_async(dispatch_get_main_queue(), ^{
197 [self durationChanged:(int) (duration / 1000000)];
201 -(void) durationChanged:(NSInteger)duration
203 time_slider.maximumValue = duration;
204 [self updateTimeWidget];