Update theme submodule
[platform/upstream/gstreamer.git] / tutorials / xcode iOS / Tutorial 4 / 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 of the 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     uri = @"https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.ogv";
70
71     gst_backend = [[GStreamerBackend alloc] init:self videoView:video_view];
72 }
73
74 - (void)viewDidDisappear:(BOOL)animated
75 {
76     if (gst_backend)
77     {
78         [gst_backend deinit];
79     }
80 }
81
82 - (void)didReceiveMemoryWarning
83 {
84     [super didReceiveMemoryWarning];
85     // Dispose of any resources that can be recreated.
86 }
87
88 /* Called when the Play button is pressed */
89 -(IBAction) play:(id)sender
90 {
91     [gst_backend play];
92     is_playing_desired = 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 }
101
102 /* Called when the time slider position has changed, either because the user dragged it or
103  * we programmatically changed its position. dragging_slider tells us which one happened */
104 - (IBAction)sliderValueChanged:(id)sender {
105     if (!dragging_slider) return;
106     // If this is a local file, allow scrub seeking, this is, seek as soon as the slider is moved.
107     if (is_local_media)
108         [gst_backend setPosition:time_slider.value];
109     [self updateTimeWidget];
110 }
111
112 /* Called when the user starts to drag the time slider */
113 - (IBAction)sliderTouchDown:(id)sender {
114     [gst_backend pause];
115     dragging_slider = YES;
116 }
117
118 /* Called when the user stops dragging the time slider */
119 - (IBAction)sliderTouchUp:(id)sender {
120     dragging_slider = NO;
121     // If this is a remote file, scrub seeking is probably not going to work smoothly enough.
122     // Therefore, perform only the seek when the slider is released.
123     if (!is_local_media)
124         [gst_backend setPosition:time_slider.value];
125     if (is_playing_desired)
126         [gst_backend play];
127 }
128
129 /* Called when the size of the main view has changed, so we can
130  * resize the sub-views in ways not allowed by storyboarding. */
131 - (void)viewDidLayoutSubviews
132 {
133     CGFloat view_width = video_container_view.bounds.size.width;
134     CGFloat view_height = video_container_view.bounds.size.height;
135
136     CGFloat correct_height = view_width * media_height / media_width;
137     CGFloat correct_width = view_height * media_width / media_height;
138
139     if (correct_height < view_height) {
140         video_height_constraint.constant = correct_height;
141         video_width_constraint.constant = view_width;
142     } else {
143         video_width_constraint.constant = correct_width;
144         video_height_constraint.constant = view_height;
145     }
146
147     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);
148 }
149
150 /*
151  * Methods from GstreamerBackendDelegate
152  */
153
154 -(void) gstreamerInitialized
155 {
156     dispatch_async(dispatch_get_main_queue(), ^{
157         play_button.enabled = TRUE;
158         pause_button.enabled = TRUE;
159         message_label.text = @"Ready";
160         [gst_backend setUri:uri];
161         is_local_media = [uri hasPrefix:@"file://"];
162         is_playing_desired = NO;
163     });
164 }
165
166 -(void) gstreamerSetUIMessage:(NSString *)message
167 {
168     dispatch_async(dispatch_get_main_queue(), ^{
169         message_label.text = message;
170     });
171 }
172
173 -(void) mediaSizeChanged:(NSInteger)width height:(NSInteger)height
174 {
175     media_width = width;
176     media_height = height;
177     dispatch_async(dispatch_get_main_queue(), ^{
178         [self viewDidLayoutSubviews];
179         [video_view setNeedsLayout];
180         [video_view layoutIfNeeded];
181     });
182 }
183
184 -(void) setCurrentPosition:(NSInteger)position duration:(NSInteger)duration
185 {
186     /* Ignore messages from the pipeline if the time sliders is being dragged */
187     if (dragging_slider) return;
188
189     dispatch_async(dispatch_get_main_queue(), ^{
190         time_slider.maximumValue = duration;
191         time_slider.value = position;
192         [self updateTimeWidget];
193     });
194 }
195
196 @end