Split out documentation into subfolders.
[platform/upstream/gstreamer.git] / examples / tutorials / xcode iOS / Tutorial 5 / VideoViewController.m
1 #import "VideoViewController.h"
2 #import "GStreamerBackend.h"
3 #import <UIKit/UIKit.h>
4
5 @interface VideoViewController () {
6     GStreamerBackend *gst_backend;
7     NSInteger media_width;                /* Width of the clip */
8     NSInteger 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 */
12 }
13
14 @end
15
16 @implementation VideoViewController
17
18 @synthesize uri;
19
20 /*
21  * Private methods
22  */
23
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
27 {
28     NSInteger position = time_slider.value / 1000;
29     NSInteger duration = time_slider.maximumValue / 1000;
30     NSString *position_txt = @" -- ";
31     NSString *duration_txt = @" -- ";
32
33     if (duration > 0) {
34         NSUInteger hours = duration / (60 * 60);
35         NSUInteger minutes = (duration / 60) % 60;
36         NSUInteger seconds = duration % 60;
37
38         duration_txt = [NSString stringWithFormat:@"%02lu:%02lu:%02lu", (unsigned long)hours, (unsigned long)minutes, (unsigned long)seconds];
39     }
40     if (position > 0) {
41         NSUInteger hours = position / (60 * 60);
42         NSUInteger minutes = (position / 60) % 60;
43         NSUInteger seconds = position % 60;
44
45         position_txt = [NSString stringWithFormat:@"%02lu:%02lu:%02lu", (unsigned long)hours, (unsigned long)minutes, (unsigned long)seconds];
46     }
47
48     NSString *text = [NSString stringWithFormat:@"%@ / %@",
49                       position_txt, duration_txt];
50
51     time_label.text = text;
52 }
53
54 /*
55  * Methods from UIViewController
56  */
57
58 - (void)viewDidLoad
59 {
60     [super viewDidLoad];
61
62     play_button.enabled = FALSE;
63     pause_button.enabled = FALSE;
64
65     /* As soon as the GStreamer backend knows the real values, these ones will be replaced */
66     media_width = 320;
67     media_height = 240;
68
69     gst_backend = [[GStreamerBackend alloc] init:self videoView:video_view];
70 }
71
72 - (void)viewDidDisappear:(BOOL)animated
73 {
74     if (gst_backend)
75     {
76         [gst_backend deinit];
77     }
78     [UIApplication sharedApplication].idleTimerDisabled = NO;
79 }
80
81 - (void)didReceiveMemoryWarning
82 {
83     [super didReceiveMemoryWarning];
84     // Dispose of any resources that can be recreated.
85 }
86
87 /* Called when the Play button is pressed */
88 -(IBAction) play:(id)sender
89 {
90     [gst_backend play];
91     is_playing_desired = YES;
92     [UIApplication sharedApplication].idleTimerDisabled = YES;
93 }
94
95 /* Called when the Pause button is pressed */
96 -(IBAction) pause:(id)sender
97 {
98     [gst_backend pause];
99     is_playing_desired = NO;
100     [UIApplication sharedApplication].idleTimerDisabled = NO;
101 }
102
103 /* Called when the time slider position has changed, either because the user dragged it or
104  * we programmatically changed its position. dragging_slider tells us which one happened */
105 - (IBAction)sliderValueChanged:(id)sender {
106     if (!dragging_slider) return;
107     // If this is a local file, allow scrub seeking, this is, seek as soon as the slider is moved.
108     if (is_local_media)
109         [gst_backend setPosition:time_slider.value];
110     [self updateTimeWidget];
111 }
112
113 /* Called when the user starts to drag the time slider */
114 - (IBAction)sliderTouchDown:(id)sender {
115     [gst_backend pause];
116     dragging_slider = YES;
117 }
118
119 /* Called when the user stops dragging the time slider */
120 - (IBAction)sliderTouchUp:(id)sender {
121     dragging_slider = NO;
122     // If this is a remote file, scrub seeking is probably not going to work smoothly enough.
123     // Therefore, perform only the seek when the slider is released.
124     if (!is_local_media)
125         [gst_backend setPosition:time_slider.value];
126     if (is_playing_desired)
127         [gst_backend play];
128 }
129
130 /* Called when the size of the main view has changed, so we can
131  * resize the sub-views in ways not allowed by storyboarding. */
132 - (void)viewDidLayoutSubviews
133 {
134     CGFloat view_width = video_container_view.bounds.size.width;
135     CGFloat view_height = video_container_view.bounds.size.height;
136
137     CGFloat correct_height = view_width * media_height / media_width;
138     CGFloat correct_width = view_height * media_width / media_height;
139
140     if (correct_height < view_height) {
141         video_height_constraint.constant = correct_height;
142         video_width_constraint.constant = view_width;
143     } else {
144         video_width_constraint.constant = correct_width;
145         video_height_constraint.constant = view_height;
146     }
147
148     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);
149 }
150
151 /*
152  * Methods from GstreamerBackendDelegate
153  */
154
155 -(void) gstreamerInitialized
156 {
157     dispatch_async(dispatch_get_main_queue(), ^{
158         play_button.enabled = TRUE;
159         pause_button.enabled = TRUE;
160         message_label.text = @"Ready";
161         [gst_backend setUri:uri];
162         is_local_media = [uri hasPrefix:@"file://"];
163         is_playing_desired = NO;
164     });
165 }
166
167 -(void) gstreamerSetUIMessage:(NSString *)message
168 {
169     dispatch_async(dispatch_get_main_queue(), ^{
170         message_label.text = message;
171     });
172 }
173
174 -(void) mediaSizeChanged:(NSInteger)width height:(NSInteger)height
175 {
176     media_width = width;
177     media_height = height;
178     dispatch_async(dispatch_get_main_queue(), ^{
179         [self viewDidLayoutSubviews];
180         [video_view setNeedsLayout];
181         [video_view layoutIfNeeded];
182     });
183 }
184
185 -(void) setCurrentPosition:(NSInteger)position duration:(NSInteger)duration
186 {
187     /* Ignore messages from the pipeline if the time sliders is being dragged */
188     if (dragging_slider) return;
189
190     dispatch_async(dispatch_get_main_queue(), ^{
191         time_slider.maximumValue = duration;
192         time_slider.value = position;
193         [self updateTimeWidget];
194     });
195 }
196
197 @end