MediaPlayerPrivateBlackBerry.cpp 30.6 KB
Newer Older
1
/*
2
 * Copyright (C) 2011, 2012 Research In Motion Limited. All rights reserved.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "config.h"

#if ENABLE(VIDEO)
#include "MediaPlayerPrivateBlackBerry.h"

#include "CookieManager.h"
25
26
#include "Credential.h"
#include "CredentialStorage.h"
27
28
29
30
31
#include "Frame.h"
#include "FrameView.h"
#include "GraphicsContext.h"
#include "HTMLNames.h"
#include "HostWindow.h"
32
33
#include "MediaStreamDescriptor.h"
#include "MediaStreamRegistry.h"
34
35
#include "NotImplemented.h"
#include "PlatformContextSkia.h"
36
#include "ProtectionSpace.h"
37
38
39
40
#include "RenderBox.h"
#include "TimeRanges.h"
#include "WebPageClient.h"

41
42
#include <BlackBerryPlatformSettings.h>
#include <FrameLoaderClientBlackBerry.h>
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <set>
#include <string>
#include <wtf/text/CString.h>

#if USE(ACCELERATED_COMPOSITING)
#include "NativeImageSkia.h"
#include "VideoLayerWebKitThread.h"
#include <GLES2/gl2.h>
#endif

using namespace std;
using namespace BlackBerry::Platform;

namespace WebCore {

// Static callback functions for factory
PassOwnPtr<MediaPlayerPrivateInterface> MediaPlayerPrivate::create(MediaPlayer* player)
{
    return adoptPtr(new MediaPlayerPrivate(player));
}

void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
{
    registrar(create, getSupportedTypes, supportsType, 0, 0, 0);
}

void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
{
71
    set<string> supported = PlatformPlayer::allSupportedMimeTypes();
72
73
74
75
76
    set<string>::iterator i = supported.begin();
    for (; i != supported.end(); i++)
        types.add(i->c_str());
}

77
MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs, const KURL&)
78
79
80
81
82
83
84
{
    if (type.isNull() || type.isEmpty()) {
        LOG(Media, "MediaPlayer does not support type; type is null or empty.");
        return MediaPlayer::IsNotSupported;
    }

    // spec says we should not return "probably" if the codecs string is empty
85
    if (PlatformPlayer::mimeTypeSupported(type.ascii().data())) {
86
87
88
89
90
91
92
93
94
        LOG(Media, "MediaPlayer supports type; cache contains type '%s'.", type.ascii().data());
        return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported;
    }
    LOG(Media, "MediaPlayer does not support type; cache doesn't contain type '%s'.", type.ascii().data());
    return MediaPlayer::IsNotSupported;
}

void MediaPlayerPrivate::notifyAppActivatedEvent(bool activated)
{
95
    PlatformPlayer::notifyAppActivatedEvent(activated);
96
97
98
99
}

void MediaPlayerPrivate::setCertificatePath(const String& caPath)
{
100
    PlatformPlayer::setCertificatePath(string(caPath.utf8().data()));
101
102
103
104
}

MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
    : m_webCorePlayer(player)
105
    , m_platformPlayer(0)
106
107
108
109
110
111
112
113
114
115
    , m_networkState(MediaPlayer::Empty)
    , m_readyState(MediaPlayer::HaveNothing)
    , m_fullscreenWebPageClient(0)
#if USE(ACCELERATED_COMPOSITING)
    , m_bufferingTimer(this, &MediaPlayerPrivate::bufferingTimerFired)
    , m_showBufferingImage(false)
    , m_mediaIsBuffering(false)
#endif
    , m_userDrivenSeekTimer(this, &MediaPlayerPrivate::userDrivenSeekTimerFired)
    , m_lastSeekTime(0)
116
    , m_lastSeekTimePending(false)
117
118
    , m_waitMetadataTimer(this, &MediaPlayerPrivate::waitMetadataTimerFired)
    , m_waitMetadataPopDialogCounter(0)
119
120
121
122
123
124
{
}

MediaPlayerPrivate::~MediaPlayerPrivate()
{
    if (isFullscreen()) {
125
        m_webCorePlayer->mediaPlayerClient()->mediaPlayerExitFullscreen();
126
127
128
129
130
131
132
    }
#if USE(ACCELERATED_COMPOSITING)
    // Remove media player from platform layer.
    if (m_platformLayer)
        static_cast<VideoLayerWebKitThread*>(m_platformLayer.get())->setMediaPlayer(0);
#endif

133
    deleteGuardedObject(m_platformPlayer);
134
135
136
137
138
139
140
141
142
}

void MediaPlayerPrivate::load(const String& url)
{
    String modifiedUrl(url);

    if (modifiedUrl.startsWith("local://")) {
        KURL kurl = KURL(KURL(), modifiedUrl);
        kurl.setProtocol("file");
143
        String tempPath(BlackBerry::Platform::Settings::instance()->applicationLocalDirectory().c_str());
144
145
146
147
148
149
150
151
152
        tempPath.append(kurl.path());
        kurl.setPath(tempPath);
        modifiedUrl = kurl.string();
    }
    if (modifiedUrl.startsWith("file://")) {
        // The QNX Multimedia Framework cannot handle filenames containing URL escape sequences.
        modifiedUrl = decodeURLEscapeSequences(modifiedUrl);
    }

153
    void* tabId = m_webCorePlayer->mediaPlayerClient()->mediaPlayerHostWindow()->platformPageClient();
154
155
156
157
158
159
160
161

    deleteGuardedObject(m_platformPlayer);
#if USE(ACCELERATED_COMPOSITING)
    m_platformPlayer = PlatformPlayer::create(this, tabId, true, modifiedUrl.utf8().data());
#else
    m_platformPlayer = PlatformPlayer::create(this, tabId, false, modifiedUrl.utf8().data());
#endif

162
163
164
165
    String cookiePairs;
    if (!url.isEmpty())
        cookiePairs = cookieManager().getCookie(KURL(ParsedURLString, url.utf8().data()), WithHttpOnlyCookies);
    if (!cookiePairs.isEmpty() && cookiePairs.utf8().data())
166
        m_platformPlayer->load(modifiedUrl.utf8().data(), m_webCorePlayer->userAgent().utf8().data(), cookiePairs.utf8().data());
167
    else
168
        m_platformPlayer->load(modifiedUrl.utf8().data(), m_webCorePlayer->userAgent().utf8().data(), 0);
169
170
171
172
}

void MediaPlayerPrivate::cancelLoad()
{
173
174
    if (m_platformPlayer)
        m_platformPlayer->cancelLoad();
175
176
177
178
}

void MediaPlayerPrivate::prepareToPlay()
{
179
180
    if (m_platformPlayer)
        m_platformPlayer->prepareToPlay();
181
182
183
184
}

void MediaPlayerPrivate::play()
{
185
186
    if (m_platformPlayer)
        m_platformPlayer->play();
187
188
189
190
}

void MediaPlayerPrivate::pause()
{
191
192
    if (m_platformPlayer)
        m_platformPlayer->pause();
193
194
195
196
197
198
199
200
201
}

bool MediaPlayerPrivate::supportsFullscreen() const
{
    return true;
}

IntSize MediaPlayerPrivate::naturalSize() const
{
202
203
204
    if (!m_platformPlayer)
        return IntSize();

205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
    // Cannot return empty size, otherwise paint() will never get called.
    // Also, the values here will affect the aspect ratio of the output rectangle that will
    // be used for renderering the video, so we must take PAR into account.
    // Now, hope that metadata has been provided before this gets called if this is a video.
    double pixelWidth = static_cast<double>(m_platformPlayer->pixelWidth());
    double pixelHeight = static_cast<double>(m_platformPlayer->pixelHeight());
    if (!m_platformPlayer->pixelWidth() || !m_platformPlayer->pixelHeight())
        pixelWidth = pixelHeight = 1.0;

    // Use floating point arithmetic to eliminate the chance of integer
    // overflow. PAR numbers can be 5 digits or more.
    double adjustedSourceWidth = static_cast<double>(m_platformPlayer->sourceWidth()) * pixelWidth / pixelHeight;
    return IntSize(static_cast<int>(adjustedSourceWidth + 0.5), m_platformPlayer->sourceHeight());
}

bool MediaPlayerPrivate::hasVideo() const
{
222
223
224
    if (m_platformPlayer)
        return m_platformPlayer->hasVideo();
    return false;
225
226
227
228
}

bool MediaPlayerPrivate::hasAudio() const
{
229
230
231
    if (m_platformPlayer)
        return m_platformPlayer->hasAudio();
    return false;
232
233
234
235
236
237
238
239
240
}

void MediaPlayerPrivate::setVisible(bool)
{
    notImplemented();
}

float MediaPlayerPrivate::duration() const
{
241
242
243
    if (m_platformPlayer)
        return m_platformPlayer->duration();
    return 0.0f;
244
245
}

246
247
248
static const double SeekSubmissionDelay = 0.1; // Reasonable throttling value.
static const double ShortMediaThreshold = SeekSubmissionDelay * 2.0;

249
250
float MediaPlayerPrivate::currentTime() const
{
251
252
253
    if (!m_platformPlayer)
        return 0.0f;

254
255
256
257
    // For very short media on the order of SeekSubmissionDelay we get
    // unwanted repeats if we don't return the most up-to-date currentTime().
    bool shortMedia = m_platformPlayer->duration() < ShortMediaThreshold;
    return m_userDrivenSeekTimer.isActive() && !shortMedia ? m_lastSeekTime: m_platformPlayer->currentTime();
258
259
260
261
}

void MediaPlayerPrivate::seek(float time)
{
262
263
264
    if (!m_platformPlayer)
        return;

265
    m_lastSeekTime = time;
266
    m_lastSeekTimePending = true;
267
    if (!m_userDrivenSeekTimer.isActive())
268
        userDrivenSeekTimerFired(0);
269
270
271
272
}

void MediaPlayerPrivate::userDrivenSeekTimerFired(Timer<MediaPlayerPrivate>*)
{
273
274
275
276
277
    if (m_lastSeekTimePending) {
        m_platformPlayer->seek(m_lastSeekTime);
        m_lastSeekTimePending = false;
        m_userDrivenSeekTimer.startOneShot(SeekSubmissionDelay);
    }
278
279
280
281
282
283
284
285
286
}

bool MediaPlayerPrivate::seeking() const
{
    return false;
}

void MediaPlayerPrivate::setRate(float rate)
{
287
288
    if (m_platformPlayer)
        m_platformPlayer->setRate(rate);
289
290
291
292
}

bool MediaPlayerPrivate::paused() const
{
293
294
295
    if (m_platformPlayer)
        return m_platformPlayer->paused();
    return false;
296
297
298
299
}

void MediaPlayerPrivate::setVolume(float volume)
{
300
301
    if (m_platformPlayer)
        m_platformPlayer->setVolume(volume);
302
303
304
305
306
307
308
309
310
311
312
313
314
315
}

MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const
{
    return m_networkState;
}

MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const
{
    return m_readyState;
}

float MediaPlayerPrivate::maxTimeSeekable() const
{
316
317
318
    if (m_platformPlayer)
        return m_platformPlayer->maxTimeSeekable();
    return 0.0f;
319
320
321
322
}

PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const
{
323
324
325
    if (!m_platformPlayer)
        return TimeRanges::create();

326
327
328
329
330
331
    RefPtr<TimeRanges> timeRanges = TimeRanges::create();
    if (float bufferLoaded = m_platformPlayer->bufferLoaded())
        timeRanges->add(0, bufferLoaded);
    return timeRanges.release();
}

332
bool MediaPlayerPrivate::didLoadingProgress() const
333
334
{
    notImplemented();
335
    return false;
336
337
338
339
340
341
342
343
344
}

void MediaPlayerPrivate::setSize(const IntSize&)
{
    notImplemented();
}

void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect)
{
345
346
347
    if (!m_platformPlayer)
        return;

348
349
350
351
352
353
354
355
356
357
#if USE(ACCELERATED_COMPOSITING)
    // Only process paint calls coming via the accelerated compositing code
    // path, where we get called with a null graphics context. See
    // LayerCompositingThread::drawTextures(). Ignore calls from the regular
    // rendering path.
    if (!context)
        m_platformPlayer->notifyOutputUpdate(BlackBerry::Platform::IntRect(rect.x(), rect.y(), rect.width(), rect.height()));
    return;
#endif

358
359
360
361
362
    paintCurrentFrameInContext(context, rect);
}

void MediaPlayerPrivate::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& rect)
{
363
364
365
366
367
368
369
    if (!hasVideo() || context->paintingDisabled() || !m_webCorePlayer->visible())
        return;

    PlatformGraphicsContext* graphics = context->platformContext();
    ASSERT(graphics);

    BlackBerry::Platform::IntRect platformRect(rect.x(), rect.y(), rect.width(), rect.height());
370
    IntRect clippedRect = m_webCorePlayer->mediaPlayerClient()->mediaPlayerWindowClipRect();
371
372
373
374
375
376
    BlackBerry::Platform::IntRect platformWindowClipRect(clippedRect.x(), clippedRect.y(), clippedRect.width(), clippedRect.height());
    m_platformPlayer->paint(graphics->canvas(), platformRect, platformWindowClipRect);
}

bool MediaPlayerPrivate::hasAvailableVideoFrame() const
{
377
378
379
    if (m_platformPlayer)
        return m_platformPlayer->hasAvailableVideoFrame();
    return false;
380
381
382
383
384
385
386
387
388
}

bool MediaPlayerPrivate::hasSingleSecurityOrigin() const
{
    return false;
}

MediaPlayer::MovieLoadType MediaPlayerPrivate::movieLoadType() const
{
389
390
391
    if (m_platformPlayer)
        return static_cast<MediaPlayer::MovieLoadType>(m_platformPlayer->movieLoadType());
    return MediaPlayer::Unknown;
392
393
394
395
396
397
398
}

void MediaPlayerPrivate::resizeSourceDimensions()
{
    if (!m_webCorePlayer)
        return;

399
    if (!m_webCorePlayer->mediaPlayerClient()->mediaPlayerIsVideo())
400
401
402
        return;

    // If we have an HTMLVideoElement but the source has no video, then we need to resize the media element.
403
    if (!hasVideo() && PlatformPlayer::MediaOK == m_platformPlayer->error()) {
404
        LayoutRect rect = m_webCorePlayer->mediaPlayerClient()->mediaPlayerContentBoxRect();
405
406
407
408

        static const int playbookMinAudioElementWidth = 300;
        static const int playbookMinAudioElementHeight = 32;
        // If the rect dimensions are less than the allowed minimum, use the minimum instead.
409
410
        int newWidth = max(rect.width().toInt(), playbookMinAudioElementWidth);
        int newHeight = max(rect.height().toInt(), playbookMinAudioElementHeight);
411

412
        m_webCorePlayer->mediaPlayerClient()->mediaPlayerSetSize(IntSize(newWidth, newHeight));
413
414
415
416
417
    }

    // If we don't know what the width and height of the video source is, then we need to set it to something sane.
    if (m_platformPlayer->sourceWidth() && m_platformPlayer->sourceHeight())
        return;
418
419
    LayoutRect rect = m_webCorePlayer->mediaPlayerClient()->mediaPlayerContentBoxRect();
    m_platformPlayer->setSourceDimension(rect.width().toUnsigned(), rect.height().toUnsigned());
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
}

void MediaPlayerPrivate::setFullscreenWebPageClient(BlackBerry::WebKit::WebPageClient* client)
{
    if (m_fullscreenWebPageClient == client)
        return;

    m_fullscreenWebPageClient = client;
    m_platformPlayer->toggleFullscreen(client);

    // The following repaint is needed especially if video is paused and
    // fullscreen is exiting, so that a MediaPlayerPrivate::paint() is
    // triggered and the code in outputUpdate() sets the correct window
    // rectangle.
    if (!client)
        m_webCorePlayer->repaint();
}

BlackBerry::Platform::Graphics::Window* MediaPlayerPrivate::getWindow()
{
    return m_platformPlayer->getWindow();
}

BlackBerry::Platform::Graphics::Window* MediaPlayerPrivate::getPeerWindow(const char* uniqueID) const
{
    return m_platformPlayer->getPeerWindow(uniqueID);
}

int MediaPlayerPrivate::getWindowPosition(unsigned& x, unsigned& y, unsigned& width, unsigned& height) const
{
    return m_platformPlayer->getWindowPosition(x, y, width, height);
}

const char* MediaPlayerPrivate::mmrContextName()
{
    return m_platformPlayer->mmrContextName();
}

float MediaPlayerPrivate::percentLoaded()
{
    if (!m_platformPlayer->duration())
        return 0;

    float buffered = 0;
    RefPtr<TimeRanges> timeRanges = this->buffered();
    for (unsigned i = 0; i < timeRanges->length(); ++i) {
        ExceptionCode ignoredException;
        float start = timeRanges->start(i, ignoredException);
        float end = timeRanges->end(i, ignoredException);
        buffered += end - start;
    }

    float loaded = buffered / m_platformPlayer->duration();
    return loaded;
}

unsigned MediaPlayerPrivate::sourceWidth()
{
    return m_platformPlayer->sourceWidth();
}

unsigned MediaPlayerPrivate::sourceHeight()
{
    return m_platformPlayer->sourceHeight();
}

void MediaPlayerPrivate::setAllowPPSVolumeUpdates(bool allow)
{
488
489
    if (m_platformPlayer)
        return m_platformPlayer->setAllowPPSVolumeUpdates(allow);
490
491
492
493
494
495
496
}

void MediaPlayerPrivate::updateStates()
{
    MediaPlayer::NetworkState oldNetworkState = m_networkState;
    MediaPlayer::ReadyState oldReadyState = m_readyState;

497
    PlatformPlayer::Error currentError = m_platformPlayer->error();
498

499
    if (currentError != PlatformPlayer::MediaOK) {
500
        m_readyState = MediaPlayer::HaveNothing;
501
        if (currentError == PlatformPlayer::MediaDecodeError)
502
            m_networkState = MediaPlayer::DecodeError;
503
504
505
        else if (currentError == PlatformPlayer::MediaMetaDataError
            || currentError == PlatformPlayer::MediaAudioReceiveError
            || currentError == PlatformPlayer::MediaVideoReceiveError)
506
507
508
            m_networkState = MediaPlayer::NetworkError;
    } else {
        switch (m_platformPlayer->mediaState()) {
509
        case PlatformPlayer::MMRPlayStateIdle:
510
511
            m_networkState = MediaPlayer::Idle;
            break;
512
        case PlatformPlayer::MMRPlayStatePlaying:
513
514
            m_networkState = MediaPlayer::Loading;
            break;
515
        case PlatformPlayer::MMRPlayStateStopped:
516
517
            m_networkState = MediaPlayer::Idle;
            break;
518
        case PlatformPlayer::MMRPlayStateUnknown:
519
520
521
522
523
        default:
            break;
        }

        switch (m_platformPlayer->state()) {
524
        case PlatformPlayer::MP_STATE_IDLE:
525
526
527
#if USE(ACCELERATED_COMPOSITING)
            setBuffering(false);
            m_mediaIsBuffering = false;
528
529
530
531
532
            // Remove media player from platform layer (remove hole punch rect).
            if (m_platformLayer) {
                static_cast<VideoLayerWebKitThread*>(m_platformLayer.get())->setMediaPlayer(0);
                m_platformLayer.clear();
            }
533
534
#endif
            if (isFullscreen())
535
                m_webCorePlayer->mediaPlayerClient()->mediaPlayerExitFullscreen();
536
            break;
537
        case PlatformPlayer::MP_STATE_ACTIVE:
538
539
540
#if USE(ACCELERATED_COMPOSITING)
            m_showBufferingImage = false;
            m_mediaIsBuffering = false;
541
542
543
            // Create platform layer for video (create hole punch rect).
            if (!m_platformLayer)
                m_platformLayer = VideoLayerWebKitThread::create(m_webCorePlayer);
544
545
#endif
            break;
546
        case PlatformPlayer::MP_STATE_UNSUPPORTED:
547
548
549
550
551
552
553
554
555
            break;
        default:
            break;
        }
        if ((duration() || movieLoadType() == MediaPlayer::LiveStream)
            && m_readyState != MediaPlayer::HaveEnoughData)
            m_readyState = MediaPlayer::HaveEnoughData;
    }

556
    if (m_readyState != oldReadyState)
557
558
559
560
561
        m_webCorePlayer->readyStateChanged();
    if (m_networkState != oldNetworkState)
        m_webCorePlayer->networkStateChanged();
}

562
563
// IPlatformPlayerListener callbacks implementation
void MediaPlayerPrivate::onStateChanged(PlatformPlayer::MpState)
564
565
566
567
{
    updateStates();
}

568
void MediaPlayerPrivate::onMediaStatusChanged(PlatformPlayer::MMRPlayState)
569
570
571
572
{
    updateStates();
}

573
void MediaPlayerPrivate::onError(PlatformPlayer::Error type)
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
{
    updateStates();
}

void MediaPlayerPrivate::onDurationChanged(float duration)
{
    updateStates();
    m_webCorePlayer->durationChanged();
}

void MediaPlayerPrivate::onTimeChanged(float)
{
    m_webCorePlayer->timeChanged();
}

void MediaPlayerPrivate::onPauseStateChanged()
{
    if (!isFullscreen())
        return;

    // Paused state change not due to local controller.
    if (m_platformPlayer->isPaused())
596
        m_webCorePlayer->mediaPlayerClient()->mediaPlayerPause();
597
598
599
600
    else {
        // The HMI fullscreen widget has resumed play. Check if the
        // pause timeout occurred.
        m_platformPlayer->processPauseTimeoutIfNecessary();
601
        m_webCorePlayer->mediaPlayerClient()->mediaPlayerPlay();
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
    }
}

void MediaPlayerPrivate::onRateChanged(float)
{
    m_webCorePlayer->rateChanged();
}

void MediaPlayerPrivate::onVolumeChanged(float volume)
{
    m_webCorePlayer->volumeChanged(volume);
}

void MediaPlayerPrivate::onRepaint()
{
    m_webCorePlayer->repaint();
}

void MediaPlayerPrivate::onSizeChanged()
{
    resizeSourceDimensions();
    if (hasVideo())
        m_webCorePlayer->sizeChanged();
}

void MediaPlayerPrivate::onPlayNotified()
{
629
    m_webCorePlayer->mediaPlayerClient()->mediaPlayerPlay();
630
631
632
633
}

void MediaPlayerPrivate::onPauseNotified()
{
634
    m_webCorePlayer->mediaPlayerClient()->mediaPlayerPause();
635
636
}

637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
static const int popupDialogInterval = 10;
static const double checkMetadataReadyInterval = 0.5;
void MediaPlayerPrivate::onWaitMetadataNotified(bool hasFinished, int timeWaited)
{
    if (!hasFinished) {
        if (!m_waitMetadataTimer.isActive()) {
            // Make sure to popup dialog every 10 seconds after metadata start to load.
            // This should be set only once at the first time when user press the play button.
            m_waitMetadataPopDialogCounter = static_cast<int>(timeWaited / checkMetadataReadyInterval);
            m_waitMetadataTimer.startOneShot(checkMetadataReadyInterval);
        }
    } else if (m_waitMetadataTimer.isActive()) {
        m_waitMetadataTimer.stop();
        m_waitMetadataPopDialogCounter = 0;
    }
}

void MediaPlayerPrivate::waitMetadataTimerFired(Timer<MediaPlayerPrivate>*)
{
    if (m_platformPlayer->isMetadataReady()) {
        m_platformPlayer->playWithMetadataReady();
        m_waitMetadataPopDialogCounter = 0;
        return;
    }

    static const int hitTimeToPopupDialog = static_cast<int>(popupDialogInterval / checkMetadataReadyInterval);
    m_waitMetadataPopDialogCounter++;
    if (m_waitMetadataPopDialogCounter < hitTimeToPopupDialog) {
        m_waitMetadataTimer.startOneShot(checkMetadataReadyInterval);
        return;
    }
    m_waitMetadataPopDialogCounter = 0;

670
    int wait = showErrorDialog(PlatformPlayer::MediaMetaDataTimeoutError);
671
672
673
674
675
676
677
678
679
680
    if (!wait)
        onPauseNotified();
    else {
        if (m_platformPlayer->isMetadataReady())
            m_platformPlayer->playWithMetadataReady();
        else
            m_waitMetadataTimer.startOneShot(checkMetadataReadyInterval);
    }
}

681
682
683
684
685
686
687
#if USE(ACCELERATED_COMPOSITING)
void MediaPlayerPrivate::onBuffering(bool flag)
{
    setBuffering(flag);
}
#endif

688
689
690
691
692
693
694
695
696
697
698
static ProtectionSpace generateProtectionSpaceFromMMRAuthChallenge(const MMRAuthChallenge& authChallenge)
{
    KURL url(ParsedURLString, String(authChallenge.url().c_str()));
    ASSERT(url.isValid());

    return ProtectionSpace(url.host(), url.port(),
                           static_cast<ProtectionSpaceServerType>(authChallenge.serverType()),
                           authChallenge.realm().c_str(),
                           static_cast<ProtectionSpaceAuthenticationScheme>(authChallenge.authScheme()));
}

699
void MediaPlayerPrivate::onAuthenticationNeeded(MMRAuthChallenge& authChallenge)
700
701
702
{
    KURL url(ParsedURLString, String(authChallenge.url().c_str()));
    if (!url.isValid())
703
        return;
704
705
706

    ProtectionSpace protectionSpace = generateProtectionSpaceFromMMRAuthChallenge(authChallenge);
    Credential credential = CredentialStorage::get(protectionSpace);
707
708
709
710
    if (!credential.isEmpty()) {
        notifyChallengeResult(url, protectionSpace, AuthenticationChallengeSuccess, credential);
        return;
    }
711

712
713
714
    if (frameView() && frameView()->hostWindow())
        frameView()->hostWindow()->platformPageClient()->authenticationChallenge(url, protectionSpace, credential, this);
}
715

716
717
718
719
void MediaPlayerPrivate::notifyChallengeResult(const KURL& url, const ProtectionSpace& protectionSpace, AuthenticationChallengeResult result, const Credential& credential)
{
    if (result != AuthenticationChallengeSuccess || !url.isValid())
        return;
720

721
722
723
    m_platformPlayer->reloadWithCredential(credential.user().utf8(true).data(),
                                           credential.password().utf8(true).data(),
                                           static_cast<MMRAuthChallenge::CredentialPersistence>(credential.persistence()));
724
725
726
727
728
729
730
731
732
733
734
735
736
737
}

void MediaPlayerPrivate::onAuthenticationAccepted(const MMRAuthChallenge& authChallenge) const
{
    KURL url(ParsedURLString, String(authChallenge.url().c_str()));
    if (!url.isValid())
        return;

    ProtectionSpace protectionSpace = generateProtectionSpaceFromMMRAuthChallenge(authChallenge);
    Credential savedCredential = CredentialStorage::get(protectionSpace);
    if (savedCredential.isEmpty())
        CredentialStorage::set(Credential(authChallenge.username().c_str(), authChallenge.password().c_str(), static_cast<CredentialPersistence>(authChallenge.persistence())), protectionSpace, url);
}

738
int MediaPlayerPrivate::showErrorDialog(PlatformPlayer::Error type)
739
740
741
742
743
{
    using namespace BlackBerry::WebKit;

    WebPageClient::AlertType atype;
    switch (type) {
744
    case PlatformPlayer::MediaOK:
745
746
        atype = WebPageClient::MediaOK;
        break;
747
    case PlatformPlayer::MediaDecodeError:
748
749
        atype = WebPageClient::MediaDecodeError;
        break;
750
    case PlatformPlayer::MediaMetaDataError:
751
752
        atype = WebPageClient::MediaMetaDataError;
        break;
753
    case PlatformPlayer::MediaMetaDataTimeoutError:
754
755
        atype = WebPageClient::MediaMetaDataTimeoutError;
        break;
756
    case PlatformPlayer::MediaNoMetaDataError:
757
758
        atype = WebPageClient::MediaNoMetaDataError;
        break;
759
    case PlatformPlayer::MediaVideoReceiveError:
760
761
        atype = WebPageClient::MediaVideoReceiveError;
        break;
762
    case PlatformPlayer::MediaAudioReceiveError:
763
764
        atype = WebPageClient::MediaAudioReceiveError;
        break;
765
    case PlatformPlayer::MediaInvalidError:
766
767
768
769
770
771
        atype = WebPageClient::MediaInvalidError;
        break;
    default:
        LOG(Media, "Alert type does not exist.");
        return -1;
    }
772
    return m_webCorePlayer->mediaPlayerClient()->mediaPlayerHostWindow()->platformPageClient()->showAlertDialog(atype);
773
774
}

775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
static WebMediaStreamSource toWebMediaStreamSource(MediaStreamSource* src)
{
    return WebMediaStreamSource(src->id().utf8().data(), static_cast<WebMediaStreamSource::Type>(src->type()), src->name().utf8().data());
}

static WebMediaStreamDescriptor toWebMediaStreamDescriptor(MediaStreamDescriptor* d)
{
    vector<WebMediaStreamSource> audioSources;
    for (size_t i = 0; i < d->numberOfAudioComponents(); i++)
        audioSources.push_back(toWebMediaStreamSource(d->audioComponent(i)->source()));

    vector<WebMediaStreamSource> videoSources;
    for (size_t i = 0; i < d->numberOfVideoComponents(); i++)
        videoSources.push_back(toWebMediaStreamSource(d->videoComponent(i)->source()));

    return WebMediaStreamDescriptor(d->label().utf8().data(), audioSources, videoSources);
}

WebMediaStreamDescriptor MediaPlayerPrivate::lookupMediaStream(const string& url)
{
    MediaStreamDescriptor* descriptor = MediaStreamRegistry::registry().lookupMediaStreamDescriptor(String::fromUTF8(url.c_str()));
    if (!descriptor)
        return WebMediaStreamDescriptor();

    return toWebMediaStreamDescriptor(descriptor);
}

802
803
BlackBerry::Platform::Graphics::Window* MediaPlayerPrivate::platformWindow()
{
804
    return m_webCorePlayer->mediaPlayerClient()->mediaPlayerHostWindow()->platformPageClient()->platformWindow();
805
806
807
808
809
810
811
}

bool MediaPlayerPrivate::isFullscreen() const
{
    return m_fullscreenWebPageClient;
}

812
813
bool MediaPlayerPrivate::isElementPaused() const
{
814
    return m_webCorePlayer->mediaPlayerClient()->mediaPlayerIsPaused();
815
816
}

817
818
bool MediaPlayerPrivate::isTabVisible() const
{
819
    return m_webCorePlayer->mediaPlayerClient()->mediaPlayerHostWindow()->platformPageClient()->isVisible();
820
821
}

822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
#if USE(ACCELERATED_COMPOSITING)
static const double BufferingAnimationDelay = 1.0 / 24;
static char* s_bufferingImageData = 0;
static int s_bufferingImageWidth = 0;
static int s_bufferingImageHeight = 0;

PlatformMedia MediaPlayerPrivate::platformMedia() const
{
    PlatformMedia pm;
    pm.type = PlatformMedia::QNXMediaPlayerType;
    pm.media.qnxMediaPlayer = const_cast<MediaPlayerPrivate*>(this);
    return pm;
}

PlatformLayer* MediaPlayerPrivate::platformLayer() const
{
    if (m_platformLayer)
        return m_platformLayer.get();
    return 0;
}

static void loadBufferingImageData()
{
    static bool loaded = false;
    if (!loaded) {
        static Image* bufferingIcon = Image::loadPlatformResource("vidbuffer").leakRef();
        NativeImageSkia* nativeImage = bufferingIcon->nativeImageForCurrentFrame();
        if (!nativeImage)
            return;

        if (!nativeImage->isDataComplete())
            return;

        loaded = true;
856
        nativeImage->bitmap().lockPixels();
857

858
859
860
        int bufSize = nativeImage->bitmap().width() * nativeImage->bitmap().height() * 4;
        s_bufferingImageWidth = nativeImage->bitmap().width();
        s_bufferingImageHeight = nativeImage->bitmap().height();
861
        s_bufferingImageData = static_cast<char*>(malloc(bufSize));
862
        memcpy(s_bufferingImageData, nativeImage->bitmap().getPixels(), bufSize);
863

864
        nativeImage->bitmap().unlockPixels();
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
        bufferingIcon->deref();
    }
}

void MediaPlayerPrivate::bufferingTimerFired(Timer<MediaPlayerPrivate>*)
{
    if (m_showBufferingImage) {
        if (!isFullscreen() && m_platformLayer)
            m_platformLayer->setNeedsDisplay();
        m_bufferingTimer.startOneShot(BufferingAnimationDelay);
    }
}

void MediaPlayerPrivate::setBuffering(bool buffering)
{
    if (!hasVideo())
        buffering = false; // Buffering animation not visible for audio.
    if (buffering != m_showBufferingImage) {
        m_showBufferingImage = buffering;
        if (buffering) {
            loadBufferingImageData();
            m_bufferingTimer.startOneShot(BufferingAnimationDelay);
        } else
            m_bufferingTimer.stop();

        if (m_platformLayer)
            m_platformLayer->setNeedsDisplay();
    }
}

static unsigned int allocateTextureId()
{
    unsigned int texid;
    glGenTextures(1, &texid);
    glBindTexture(GL_TEXTURE_2D, texid);
    // Do basic linear filtering on resize.
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // NPOT textures in GL ES only work when the wrap mode is set to GL_CLAMP_TO_EDGE.
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    return texid;
}

void MediaPlayerPrivate::drawBufferingAnimation(const TransformationMatrix& matrix, int positionLocation, int texCoordLocation)
{
    if (m_showBufferingImage && s_bufferingImageData && !isFullscreen()) {
        TransformationMatrix renderMatrix = matrix;

        // Rotate the buffering indicator so that it takes 1 second to do 1 revolution.
        timespec time;
        clock_gettime(CLOCK_REALTIME, &time);
        renderMatrix.rotate(time.tv_nsec / 1000000000.0 * 360.0);

        static bool initialized = false;
        static unsigned int texId = allocateTextureId();
        glBindTexture(GL_TEXTURE_2D, texId);
        if (!initialized) {
            initialized = true;
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, s_bufferingImageWidth, s_bufferingImageHeight,
                0, GL_RGBA, GL_UNSIGNED_BYTE, s_bufferingImageData);
            free(s_bufferingImageData);
        }

        float texcoords[] = { 0, 0,  0, 1,  1, 1,  1, 0 };
        FloatPoint vertices[4];
        float bx = s_bufferingImageWidth / 2.0;
        float by = s_bufferingImageHeight / 2.0;
        vertices[0] = renderMatrix.mapPoint(FloatPoint(-bx, -by));
        vertices[1] = renderMatrix.mapPoint(FloatPoint(-bx, by));
        vertices[2] = renderMatrix.mapPoint(FloatPoint(bx, by));
        vertices[3] = renderMatrix.mapPoint(FloatPoint(bx, -by));

        glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, vertices);
        glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, texcoords);
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    }
}
#endif

} // namespace WebCore

#endif // ENABLE(VIDEO)