44 |
44 |
45 #include "qt7backend.h" |
45 #include "qt7backend.h" |
46 |
46 |
47 #include "qt7playersession.h" |
47 #include "qt7playersession.h" |
48 #include "qt7playercontrol.h" |
48 #include "qt7playercontrol.h" |
49 #include "qt7videooutputcontrol.h" |
49 #include "qt7videooutput.h" |
50 |
50 |
|
51 #include <QtNetwork/qnetworkcookie.h> |
51 #include <qmediaplaylistnavigator.h> |
52 #include <qmediaplaylistnavigator.h> |
52 |
53 |
53 #include <CoreFoundation/CoreFoundation.h> |
54 #include <CoreFoundation/CoreFoundation.h> |
|
55 #include <Foundation/Foundation.h> |
|
56 |
|
57 #include <QtCore/qdatetime.h> |
54 |
58 |
55 #include <QtCore/qurl.h> |
59 #include <QtCore/qurl.h> |
56 #include <QtCore/qdebug.h> |
60 #include <QtCore/qdebug.h> |
57 |
61 |
58 QT_USE_NAMESPACE |
62 QT_USE_NAMESPACE |
65 } |
69 } |
66 |
70 |
67 - (QTMovieObserver *) initWithPlayerSession:(QT7PlayerSession*)session; |
71 - (QTMovieObserver *) initWithPlayerSession:(QT7PlayerSession*)session; |
68 - (void) setMovie:(QTMovie *)movie; |
72 - (void) setMovie:(QTMovie *)movie; |
69 - (void) processEOS:(NSNotification *)notification; |
73 - (void) processEOS:(NSNotification *)notification; |
70 - (void) processStateChange:(NSNotification *)notification; |
74 - (void) processLoadStateChange:(NSNotification *)notification; |
|
75 - (void) processVolumeChange:(NSNotification *)notification; |
|
76 - (void) processNaturalSizeChange :(NSNotification *)notification; |
71 @end |
77 @end |
72 |
78 |
73 @implementation QTMovieObserver |
79 @implementation QTMovieObserver |
74 |
80 |
75 - (QTMovieObserver *) initWithPlayerSession:(QT7PlayerSession*)session |
81 - (QTMovieObserver *) initWithPlayerSession:(QT7PlayerSession*)session |
92 } |
98 } |
93 |
99 |
94 m_movie = movie; |
100 m_movie = movie; |
95 |
101 |
96 if (movie) { |
102 if (movie) { |
97 [[NSNotificationCenter defaultCenter] addObserver: self selector: |
103 [[NSNotificationCenter defaultCenter] addObserver:self |
98 @selector(processEOS:) name: QTMovieDidEndNotification object: m_movie]; |
104 selector:@selector(processEOS:) |
99 |
105 name:QTMovieDidEndNotification |
100 [[NSNotificationCenter defaultCenter] addObserver: self selector: |
106 object:m_movie]; |
101 @selector(processStateChange:) name: QTMovieLoadStateDidChangeNotification object: m_movie]; |
107 |
102 |
108 [[NSNotificationCenter defaultCenter] addObserver:self |
103 [[NSNotificationCenter defaultCenter] addObserver: self selector: |
109 selector:@selector(processLoadStateChange:) |
104 @selector(processVolumeChange:) name: QTMovieVolumeDidChangeNotification object: m_movie]; |
110 name:QTMovieLoadStateDidChangeNotification |
105 |
111 object:m_movie]; |
|
112 |
|
113 [[NSNotificationCenter defaultCenter] addObserver:self |
|
114 selector:@selector(processVolumeChange:) |
|
115 name:QTMovieVolumeDidChangeNotification |
|
116 object:m_movie]; |
|
117 |
|
118 [[NSNotificationCenter defaultCenter] addObserver:self |
|
119 selector:@selector(processNaturalSizeChange:) |
|
120 name: |
|
121 #if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6) |
|
122 QTMovieNaturalSizeDidChangeNotification |
|
123 #else |
|
124 QTMovieEditedNotification |
|
125 #endif |
|
126 object:m_movie]; |
106 [movie retain]; |
127 [movie retain]; |
107 } |
128 } |
108 } |
129 } |
109 |
130 |
110 - (void) processEOS:(NSNotification *)notification |
131 - (void) processEOS:(NSNotification *)notification |
111 { |
132 { |
112 Q_UNUSED(notification); |
133 Q_UNUSED(notification); |
113 m_session->processEOS(); |
134 QMetaObject::invokeMethod(m_session, "processEOS", Qt::AutoConnection); |
114 } |
135 } |
115 |
136 |
116 - (void) processStateChange:(NSNotification *)notification |
137 - (void) processLoadStateChange:(NSNotification *)notification |
117 { |
138 { |
118 Q_UNUSED(notification); |
139 Q_UNUSED(notification); |
119 m_session->processStateChange(); |
140 QMetaObject::invokeMethod(m_session, "processLoadStateChange", Qt::AutoConnection); |
120 } |
141 } |
121 |
142 |
122 - (void) processVolumeChange:(NSNotification *)notification |
143 - (void) processVolumeChange:(NSNotification *)notification |
123 { |
144 { |
124 Q_UNUSED(notification); |
145 Q_UNUSED(notification); |
125 m_session->processVolumeChange(); |
146 QMetaObject::invokeMethod(m_session, "processVolumeChange", Qt::AutoConnection); |
126 } |
147 } |
127 |
148 |
|
149 - (void) processNaturalSizeChange :(NSNotification *)notification |
|
150 { |
|
151 Q_UNUSED(notification); |
|
152 QMetaObject::invokeMethod(m_session, "processNaturalSizeChange", Qt::AutoConnection); |
|
153 } |
128 |
154 |
129 @end |
155 @end |
130 |
156 |
131 static CFStringRef qString2CFStringRef(const QString &string) |
157 static inline NSString *qString2CFStringRef(const QString &string) |
132 { |
158 { |
133 return CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar *>(string.unicode()), |
159 return [NSString stringWithCharacters:reinterpret_cast<const UniChar *>(string.unicode()) length:string.length()]; |
134 string.length()); |
|
135 } |
160 } |
136 |
161 |
137 QT7PlayerSession::QT7PlayerSession(QObject *parent) |
162 QT7PlayerSession::QT7PlayerSession(QObject *parent) |
138 : QObject(parent) |
163 : QObject(parent) |
139 , m_QTMovie(0) |
164 , m_QTMovie(0) |
162 void QT7PlayerSession::setVideoOutput(QT7VideoOutput *output) |
191 void QT7PlayerSession::setVideoOutput(QT7VideoOutput *output) |
163 { |
192 { |
164 if (m_videoOutput == output) |
193 if (m_videoOutput == output) |
165 return; |
194 return; |
166 |
195 |
167 qDebug() << "set output" << output; |
196 if (m_videoOutput) |
168 |
|
169 if (m_videoOutput) { |
|
170 m_videoOutput->setEnabled(false); |
|
171 m_videoOutput->setMovie(0); |
197 m_videoOutput->setMovie(0); |
172 } |
|
173 |
198 |
174 m_videoOutput = output; |
199 m_videoOutput = output; |
175 |
200 |
176 if (m_videoOutput) { |
201 if (m_videoOutput && m_state != QMediaPlayer::StoppedState) |
177 m_videoOutput->setEnabled(m_QTMovie != 0); |
|
178 m_videoOutput->setMovie(m_QTMovie); |
202 m_videoOutput->setMovie(m_QTMovie); |
179 } |
203 } |
180 } |
|
181 |
|
182 |
204 |
183 qint64 QT7PlayerSession::position() const |
205 qint64 QT7PlayerSession::position() const |
184 { |
206 { |
185 if (!m_QTMovie || m_state == QMediaPlayer::PausedState) |
207 if (!m_QTMovie || m_state == QMediaPlayer::PausedState) |
186 return m_currentTime; |
208 return m_currentTime; |
268 [(QTMovie*)m_QTMovie setCurrentTime:newQTTime]; |
290 [(QTMovie*)m_QTMovie setCurrentTime:newQTTime]; |
269 } |
291 } |
270 |
292 |
271 void QT7PlayerSession::play() |
293 void QT7PlayerSession::play() |
272 { |
294 { |
|
295 if (m_videoOutput) |
|
296 m_videoOutput->setMovie(m_QTMovie); |
|
297 |
273 float preferredRate = [[(QTMovie*)m_QTMovie attributeForKey:@"QTMoviePreferredRateAttribute"] floatValue]; |
298 float preferredRate = [[(QTMovie*)m_QTMovie attributeForKey:@"QTMoviePreferredRateAttribute"] floatValue]; |
274 [(QTMovie*)m_QTMovie setRate:preferredRate*m_rate]; |
299 [(QTMovie*)m_QTMovie setRate:preferredRate*m_rate]; |
275 |
300 |
276 if (m_state != QMediaPlayer::PlayingState) |
301 if (m_state != QMediaPlayer::PlayingState) |
277 emit stateChanged(m_state = QMediaPlayer::PlayingState); |
302 emit stateChanged(m_state = QMediaPlayer::PlayingState); |
278 } |
303 } |
279 |
304 |
280 void QT7PlayerSession::pause() |
305 void QT7PlayerSession::pause() |
281 { |
306 { |
|
307 if (m_videoOutput) |
|
308 m_videoOutput->setMovie(m_QTMovie); |
|
309 |
282 m_state = QMediaPlayer::PausedState; |
310 m_state = QMediaPlayer::PausedState; |
283 |
311 |
284 [(QTMovie*)m_QTMovie setRate:0]; |
312 [(QTMovie*)m_QTMovie setRate:0]; |
285 |
313 |
286 emit stateChanged(m_state); |
314 emit stateChanged(m_state); |
329 |
360 |
330 void QT7PlayerSession::setMedia(const QMediaContent &content, QIODevice *stream) |
361 void QT7PlayerSession::setMedia(const QMediaContent &content, QIODevice *stream) |
331 { |
362 { |
332 AutoReleasePool pool; |
363 AutoReleasePool pool; |
333 |
364 |
|
365 qDebug() << "SetMedia" << content.canonicalUrl(); |
|
366 |
334 if (m_QTMovie) { |
367 if (m_QTMovie) { |
335 [(QTMovieObserver*)m_movieObserver setMovie:nil]; |
368 [(QTMovieObserver*)m_movieObserver setMovie:nil]; |
336 |
369 |
337 if (m_videoOutput) { |
370 if (m_videoOutput) |
338 m_videoOutput->setEnabled(false); |
|
339 m_videoOutput->setMovie(0); |
371 m_videoOutput->setMovie(0); |
340 } |
|
341 |
372 |
342 [(QTMovie*)m_QTMovie release]; |
373 [(QTMovie*)m_QTMovie release]; |
343 m_QTMovie = 0; |
374 m_QTMovie = 0; |
344 } |
375 } |
345 |
376 |
346 m_resources = content; |
377 m_resources = content; |
347 m_mediaStream = stream; |
378 m_mediaStream = stream; |
348 m_mediaStatus = QMediaPlayer::NoMedia; |
379 m_mediaStatus = QMediaPlayer::NoMedia; |
349 |
380 |
350 QUrl url; |
381 QNetworkRequest request; |
351 |
|
352 if (!content.isNull()) |
382 if (!content.isNull()) |
353 url = content.canonicalUrl(); |
383 request = content.canonicalResource().request(); |
354 else |
384 else |
355 return; |
385 return; |
356 |
386 |
|
387 QVariant cookies = request.header(QNetworkRequest::CookieHeader); |
|
388 if (cookies.isValid()) { |
|
389 NSHTTPCookieStorage *store = [NSHTTPCookieStorage sharedHTTPCookieStorage]; |
|
390 QList<QNetworkCookie> cookieList = cookies.value<QList<QNetworkCookie> >(); |
|
391 |
|
392 foreach (const QNetworkCookie &requestCookie, cookieList) { |
|
393 NSMutableDictionary *p = [NSMutableDictionary dictionaryWithObjectsAndKeys: |
|
394 qString2CFStringRef(requestCookie.name()), NSHTTPCookieName, |
|
395 qString2CFStringRef(requestCookie.value()), NSHTTPCookieValue, |
|
396 qString2CFStringRef(requestCookie.domain()), NSHTTPCookieDomain, |
|
397 qString2CFStringRef(requestCookie.path()), NSHTTPCookiePath, |
|
398 nil |
|
399 ]; |
|
400 if (requestCookie.isSessionCookie()) |
|
401 [p setObject:[NSString stringWithUTF8String:"TRUE"] forKey:NSHTTPCookieDiscard]; |
|
402 else |
|
403 [p setObject:[NSDate dateWithTimeIntervalSince1970:requestCookie.expirationDate().toTime_t()] forKey:NSHTTPCookieExpires]; |
|
404 |
|
405 [store setCookie:[NSHTTPCookie cookieWithProperties:p]]; |
|
406 } |
|
407 } |
|
408 |
|
409 |
|
410 QUrl requestUrl = request.url(); |
|
411 if (requestUrl.scheme().isEmpty()) |
|
412 requestUrl.setScheme(QLatin1String("file")); |
|
413 |
|
414 qDebug() << "Play" << requestUrl; |
|
415 |
357 NSError *err = 0; |
416 NSError *err = 0; |
358 QTDataReference *dataRef = 0; |
417 NSString *urlString = qString2CFStringRef(requestUrl.toString()); |
359 |
|
360 if ( url.scheme() == "file" ) { |
|
361 NSString *nsFileName = (NSString *)qString2CFStringRef( url.toLocalFile() ); |
|
362 dataRef = [QTDataReference dataReferenceWithReferenceToFile:nsFileName]; |
|
363 } else { |
|
364 NSString *urlString = (NSString *)qString2CFStringRef( url.toString() ); |
|
365 NSURL *url = [NSURL URLWithString: urlString]; |
|
366 dataRef = [QTDataReference dataReferenceWithReferenceToURL:url]; |
|
367 } |
|
368 |
418 |
369 NSDictionary *attr = [NSDictionary dictionaryWithObjectsAndKeys: |
419 NSDictionary *attr = [NSDictionary dictionaryWithObjectsAndKeys: |
370 dataRef, QTMovieDataReferenceAttribute, |
420 [NSURL URLWithString:urlString], QTMovieURLAttribute, |
371 [NSNumber numberWithBool:YES], QTMovieOpenAsyncOKAttribute, |
421 [NSNumber numberWithBool:YES], QTMovieOpenAsyncOKAttribute, |
372 [NSNumber numberWithBool:YES], QTMovieIsActiveAttribute, |
422 [NSNumber numberWithBool:YES], QTMovieIsActiveAttribute, |
373 [NSNumber numberWithBool:YES], QTMovieResolveDataRefsAttribute, |
423 [NSNumber numberWithBool:YES], QTMovieResolveDataRefsAttribute, |
374 [NSNumber numberWithBool:YES], QTMovieDontInteractWithUserAttribute, |
424 [NSNumber numberWithBool:YES], QTMovieDontInteractWithUserAttribute, |
375 nil]; |
425 nil]; |
416 } |
465 } |
417 |
466 |
418 void QT7PlayerSession::processEOS() |
467 void QT7PlayerSession::processEOS() |
419 { |
468 { |
420 m_mediaStatus = QMediaPlayer::EndOfMedia; |
469 m_mediaStatus = QMediaPlayer::EndOfMedia; |
|
470 if (m_videoOutput) |
|
471 m_videoOutput->setMovie(0); |
421 emit stateChanged(m_state = QMediaPlayer::StoppedState); |
472 emit stateChanged(m_state = QMediaPlayer::StoppedState); |
422 emit mediaStatusChanged(m_mediaStatus); |
473 emit mediaStatusChanged(m_mediaStatus); |
423 } |
474 } |
424 |
475 |
425 void QT7PlayerSession::processStateChange() |
476 void QT7PlayerSession::processLoadStateChange() |
426 { |
477 { |
|
478 if (!m_QTMovie) |
|
479 return; |
|
480 |
427 signed long state = [[(QTMovie*)m_QTMovie attributeForKey:QTMovieLoadStateAttribute] |
481 signed long state = [[(QTMovie*)m_QTMovie attributeForKey:QTMovieLoadStateAttribute] |
428 longValue]; |
482 longValue]; |
429 //qDebug() << "new State:" << state; |
483 qDebug() << "Moview load state changed:" << state; |
430 |
484 |
431 #ifndef QUICKTIME_C_API_AVAILABLE |
485 #ifndef QUICKTIME_C_API_AVAILABLE |
432 enum { |
486 enum { |
433 kMovieLoadStateError = -1L, |
487 kMovieLoadStateError = -1L, |
434 kMovieLoadStateLoading = 1000, |
488 kMovieLoadStateLoading = 1000, |
449 else if (state >= kMovieLoadStateLoading) |
503 else if (state >= kMovieLoadStateLoading) |
450 newStatus = isPlaying ? QMediaPlayer::StalledMedia : QMediaPlayer::LoadingMedia; |
504 newStatus = isPlaying ? QMediaPlayer::StalledMedia : QMediaPlayer::LoadingMedia; |
451 |
505 |
452 if (state == kMovieLoadStateError) { |
506 if (state == kMovieLoadStateError) { |
453 newStatus = QMediaPlayer::InvalidMedia; |
507 newStatus = QMediaPlayer::InvalidMedia; |
454 emit error(QMediaPlayer::FormatError, tr("Playback failed")); |
508 if (m_videoOutput) |
455 } |
509 m_videoOutput->setMovie(0); |
456 |
510 |
457 if (newStatus != m_mediaStatus) { |
511 emit error(QMediaPlayer::FormatError, tr("Failed to load media")); |
458 switch (newStatus) { |
512 emit stateChanged(m_state = QMediaPlayer::StoppedState); |
459 case QMediaPlayer::BufferedMedia: |
513 } |
460 case QMediaPlayer::BufferingMedia: |
514 |
461 //delayed playback start is necessary for network sources |
515 if (state >= kMovieLoadStatePlayable && |
462 if (m_state == QMediaPlayer::PlayingState) { |
516 m_state == QMediaPlayer::PlayingState && |
463 QMetaObject::invokeMethod(this, "play", Qt::QueuedConnection); |
517 [(QTMovie*)m_QTMovie rate] == 0) { |
464 } |
518 QMetaObject::invokeMethod(this, "play", Qt::QueuedConnection); |
465 //fall |
519 } |
466 case QMediaPlayer::LoadedMedia: |
520 |
467 case QMediaPlayer::LoadingMedia: |
521 if (state >= kMovieLoadStateLoaded) { |
468 emit durationChanged(duration()); |
522 qint64 currentDuration = duration(); |
469 emit audioAvailableChanged(isAudioAvailable()); |
523 if (m_duration != currentDuration) |
470 emit videoAvailableChanged(isVideoAvailable()); |
524 emit durationChanged(m_duration = currentDuration); |
471 break; |
525 |
472 case QMediaPlayer::InvalidMedia: |
526 if (m_audioAvailable != isAudioAvailable()) |
473 emit stateChanged(m_state = QMediaPlayer::StoppedState); |
527 emit audioAvailableChanged(m_audioAvailable = !m_audioAvailable); |
474 default: |
528 |
475 break; |
529 if (m_videoAvailable != isVideoAvailable()) |
476 } |
530 emit videoAvailableChanged(m_videoAvailable = !m_videoAvailable); |
477 |
531 } |
|
532 |
|
533 if (newStatus != m_mediaStatus) |
478 emit mediaStatusChanged(m_mediaStatus = newStatus); |
534 emit mediaStatusChanged(m_mediaStatus = newStatus); |
479 } |
|
480 } |
535 } |
481 |
536 |
482 void QT7PlayerSession::processVolumeChange() |
537 void QT7PlayerSession::processVolumeChange() |
483 { |
538 { |
484 if (!m_QTMovie) |
539 if (!m_QTMovie) |