PreviewPlayer.cpp revision 90b6191067990a7a3ee947d7ce08c64f780f0de7
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18// #define LOG_NDEBUG 0
19#define LOG_TAG "PreviewPlayer"
20#include <utils/Log.h>
21
22#include <binder/IPCThreadState.h>
23#include <binder/IServiceManager.h>
24#include <media/IMediaPlayerService.h>
25#include <media/stagefright/DataSource.h>
26#include <media/stagefright/MediaBuffer.h>
27#include <media/stagefright/MediaDefs.h>
28#include <media/stagefright/MediaExtractor.h>
29#include <media/stagefright/MediaSource.h>
30#include <media/stagefright/MetaData.h>
31#include <media/stagefright/OMXCodec.h>
32#include <media/stagefright/foundation/ADebug.h>
33#include <gui/Surface.h>
34#include <gui/ISurfaceTexture.h>
35#include <gui/SurfaceTextureClient.h>
36
37#include "VideoEditorPreviewController.h"
38#include "DummyAudioSource.h"
39#include "DummyVideoSource.h"
40#include "VideoEditorSRC.h"
41#include "PreviewPlayer.h"
42
43namespace android {
44
45
46void addBatteryData(uint32_t params) {
47    sp<IBinder> binder =
48        defaultServiceManager()->getService(String16("media.player"));
49    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
50    CHECK(service.get() != NULL);
51
52    service->addBatteryData(params);
53}
54
55struct PreviewPlayerEvent : public TimedEventQueue::Event {
56    PreviewPlayerEvent(
57            PreviewPlayer *player,
58            void (PreviewPlayer::*method)())
59        : mPlayer(player),
60          mMethod(method) {
61    }
62
63protected:
64    virtual ~PreviewPlayerEvent() {}
65
66    virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
67        (mPlayer->*mMethod)();
68    }
69
70private:
71    PreviewPlayer *mPlayer;
72    void (PreviewPlayer::*mMethod)();
73
74    PreviewPlayerEvent(const PreviewPlayerEvent &);
75    PreviewPlayerEvent &operator=(const PreviewPlayerEvent &);
76};
77
78PreviewPlayer::PreviewPlayer(NativeWindowRenderer* renderer)
79    : mQueueStarted(false),
80      mTimeSource(NULL),
81      mVideoRendererIsPreview(false),
82      mAudioPlayer(NULL),
83      mDisplayWidth(0),
84      mDisplayHeight(0),
85      mFlags(0),
86      mExtractorFlags(0),
87      mVideoBuffer(NULL),
88      mLastVideoTimeUs(-1),
89      mNativeWindowRenderer(renderer),
90      mCurrFramingEffectIndex(0),
91      mFrameRGBBuffer(NULL),
92      mFrameYUVBuffer(NULL) {
93
94    CHECK_EQ(mClient.connect(), (status_t)OK);
95    DataSource::RegisterDefaultSniffers();
96
97
98    mVideoRenderer = NULL;
99    mEffectsSettings = NULL;
100    mAudioPlayer = NULL;
101    mAudioMixStoryBoardTS = 0;
102    mCurrentMediaBeginCutTime = 0;
103    mCurrentMediaVolumeValue = 0;
104    mNumberEffects = 0;
105    mDecodedVideoTs = 0;
106    mDecVideoTsStoryBoard = 0;
107    mCurrentVideoEffect = VIDEO_EFFECT_NONE;
108    mProgressCbInterval = 0;
109    mNumberDecVideoFrames = 0;
110    mOverlayUpdateEventPosted = false;
111    mIsChangeSourceRequired = true;
112
113    mVideoEvent = new PreviewPlayerEvent(this, &PreviewPlayer::onVideoEvent);
114    mVideoEventPending = false;
115    mVideoLagEvent = new PreviewPlayerEvent(this, &PreviewPlayer::onVideoLagUpdate);
116    mVideoEventPending = false;
117    mCheckAudioStatusEvent = new PreviewPlayerEvent(
118            this, &PreviewPlayer::onCheckAudioStatus);
119    mAudioStatusEventPending = false;
120    mStreamDoneEvent = new PreviewPlayerEvent(
121            this, &PreviewPlayer::onStreamDone);
122    mStreamDoneEventPending = false;
123    mProgressCbEvent = new PreviewPlayerEvent(this,
124         &PreviewPlayer::onProgressCbEvent);
125
126    mOverlayUpdateEvent = new PreviewPlayerEvent(this,
127        &PreviewPlayer::onUpdateOverlayEvent);
128    mProgressCbEventPending = false;
129
130    mOverlayUpdateEventPending = false;
131    mRenderingMode = (M4xVSS_MediaRendering)MEDIA_RENDERING_INVALID;
132    mIsFiftiesEffectStarted = false;
133    reset();
134}
135
136PreviewPlayer::~PreviewPlayer() {
137
138    if (mQueueStarted) {
139        mQueue.stop();
140    }
141
142    reset();
143
144    if (mVideoRenderer) {
145        mNativeWindowRenderer->destroyRenderInput(mVideoRenderer);
146    }
147
148    Mutex::Autolock lock(mLock);
149    clear_l();
150    mClient.disconnect();
151}
152
153void PreviewPlayer::cancelPlayerEvents_l(bool updateProgressCb) {
154    mQueue.cancelEvent(mVideoEvent->eventID());
155    mVideoEventPending = false;
156    mQueue.cancelEvent(mStreamDoneEvent->eventID());
157    mStreamDoneEventPending = false;
158    mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
159    mAudioStatusEventPending = false;
160    mQueue.cancelEvent(mVideoLagEvent->eventID());
161    mVideoLagEventPending = false;
162    if (updateProgressCb) {
163        mQueue.cancelEvent(mProgressCbEvent->eventID());
164        mProgressCbEventPending = false;
165    }
166}
167
168status_t PreviewPlayer::setDataSource(const char *path) {
169    Mutex::Autolock autoLock(mLock);
170    return setDataSource_l(path);
171}
172
173status_t PreviewPlayer::setDataSource_l(const char *path) {
174    reset_l();
175
176    mUri = path;
177
178    // The actual work will be done during preparation in the call to
179    // ::finishSetDataSource_l to avoid blocking the calling thread in
180    // setDataSource for any significant time.
181    return OK;
182}
183
184status_t PreviewPlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
185    bool haveAudio = false;
186    bool haveVideo = false;
187    for (size_t i = 0; i < extractor->countTracks(); ++i) {
188        sp<MetaData> meta = extractor->getTrackMetaData(i);
189
190        const char *mime;
191        CHECK(meta->findCString(kKeyMIMEType, &mime));
192
193        if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
194            setVideoSource(extractor->getTrack(i));
195            haveVideo = true;
196        } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
197            setAudioSource(extractor->getTrack(i));
198            haveAudio = true;
199
200            if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
201                // Only do this for vorbis audio, none of the other audio
202                // formats even support this ringtone specific hack and
203                // retrieving the metadata on some extractors may turn out
204                // to be very expensive.
205                sp<MetaData> fileMeta = extractor->getMetaData();
206                int32_t loop;
207                if (fileMeta != NULL
208                        && fileMeta->findInt32(kKeyAutoLoop, &loop)
209                         && loop != 0) {
210                    mFlags |= AUTO_LOOPING;
211                }
212            }
213        }
214
215        if (haveAudio && haveVideo) {
216            break;
217        }
218    }
219
220    /* Add the support for Dummy audio*/
221    if( !haveAudio ){
222        mAudioTrack = DummyAudioSource::Create(32000, 2, 20000,
223                                              ((mPlayEndTimeMsec)*1000LL));
224        if(mAudioTrack != NULL) {
225            haveAudio = true;
226        }
227    }
228
229    if (!haveAudio && !haveVideo) {
230        return UNKNOWN_ERROR;
231    }
232
233    mExtractorFlags = extractor->flags();
234    return OK;
235}
236
237status_t PreviewPlayer::setDataSource_l_jpg() {
238    ALOGV("setDataSource_l_jpg");
239
240    M4OSA_ERR err = M4NO_ERROR;
241
242    mAudioSource = DummyAudioSource::Create(32000, 2, 20000,
243                                          ((mPlayEndTimeMsec)*1000LL));
244    if(mAudioSource != NULL) {
245        setAudioSource(mAudioSource);
246    }
247    status_t error = mAudioSource->start();
248    if (error != OK) {
249        ALOGE("Error starting dummy audio source");
250        mAudioSource.clear();
251        return err;
252    }
253
254    mDurationUs = (mPlayEndTimeMsec - mPlayBeginTimeMsec)*1000LL;
255
256    mVideoSource = DummyVideoSource::Create(mVideoWidth, mVideoHeight,
257                                            mDurationUs, mUri);
258
259    updateSizeToRender(mVideoSource->getFormat());
260    setVideoSource(mVideoSource);
261    status_t err1 = mVideoSource->start();
262    if (err1 != OK) {
263        mVideoSource.clear();
264        return err;
265    }
266
267    mIsVideoSourceJpg = true;
268    return OK;
269}
270
271void PreviewPlayer::reset_l() {
272
273    if (mFlags & PREPARING) {
274        mFlags |= PREPARE_CANCELLED;
275    }
276
277    while (mFlags & PREPARING) {
278        mPreparedCondition.wait(mLock);
279    }
280
281    cancelPlayerEvents_l();
282    mAudioTrack.clear();
283    mVideoTrack.clear();
284
285    // Shutdown audio first, so that the respone to the reset request
286    // appears to happen instantaneously as far as the user is concerned
287    // If we did this later, audio would continue playing while we
288    // shutdown the video-related resources and the player appear to
289    // not be as responsive to a reset request.
290    if (mAudioPlayer == NULL && mAudioSource != NULL) {
291        // If we had an audio player, it would have effectively
292        // taken possession of the audio source and stopped it when
293        // _it_ is stopped. Otherwise this is still our responsibility.
294        mAudioSource->stop();
295    }
296    mAudioSource.clear();
297
298    mTimeSource = NULL;
299
300    //Single audio player instance used
301    //So donot delete it here
302    //It is deleted from PreviewController class
303    //delete mAudioPlayer;
304    mAudioPlayer = NULL;
305
306    if (mVideoBuffer) {
307        mVideoBuffer->release();
308        mVideoBuffer = NULL;
309    }
310
311    if (mVideoSource != NULL) {
312        mVideoSource->stop();
313
314        // The following hack is necessary to ensure that the OMX
315        // component is completely released by the time we may try
316        // to instantiate it again.
317        wp<MediaSource> tmp = mVideoSource;
318        mVideoSource.clear();
319        while (tmp.promote() != NULL) {
320            usleep(1000);
321        }
322        IPCThreadState::self()->flushCommands();
323    }
324
325    mDurationUs = -1;
326    mFlags = 0;
327    mExtractorFlags = 0;
328    mVideoWidth = mVideoHeight = -1;
329    mTimeSourceDeltaUs = 0;
330    mVideoTimeUs = 0;
331
332    mSeeking = NO_SEEK;
333    mSeekNotificationSent = false;
334    mSeekTimeUs = 0;
335
336    mUri.setTo("");
337
338    mCurrentVideoEffect = VIDEO_EFFECT_NONE;
339    mIsVideoSourceJpg = false;
340    mFrameRGBBuffer = NULL;
341    if(mFrameYUVBuffer != NULL) {
342        free(mFrameYUVBuffer);
343        mFrameYUVBuffer = NULL;
344    }
345}
346
347status_t PreviewPlayer::play() {
348    ALOGV("play");
349    Mutex::Autolock autoLock(mLock);
350
351    mFlags &= ~CACHE_UNDERRUN;
352    mFlags &= ~INFORMED_AV_EOS;
353    return play_l();
354}
355
356status_t PreviewPlayer::startAudioPlayer_l() {
357    ALOGV("startAudioPlayer_l");
358    CHECK(!(mFlags & AUDIO_RUNNING));
359
360    if (mAudioSource == NULL || mAudioPlayer == NULL) {
361        return OK;
362    }
363
364    if (!(mFlags & AUDIOPLAYER_STARTED)) {
365        mFlags |= AUDIOPLAYER_STARTED;
366
367        // We've already started the MediaSource in order to enable
368        // the prefetcher to read its data.
369        status_t err = mAudioPlayer->start(
370                true /* sourceAlreadyStarted */);
371
372        if (err != OK) {
373            notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
374            return err;
375        }
376    } else {
377        mAudioPlayer->resume();
378    }
379
380    mFlags |= AUDIO_RUNNING;
381
382    mWatchForAudioEOS = true;
383
384    return OK;
385}
386
387status_t PreviewPlayer::setAudioPlayer(VideoEditorAudioPlayer *audioPlayer) {
388    ALOGV("setAudioPlayer");
389    Mutex::Autolock autoLock(mLock);
390    CHECK(!(mFlags & PLAYING));
391    mAudioPlayer = audioPlayer;
392
393    ALOGV("SetAudioPlayer");
394    mIsChangeSourceRequired = true;
395
396    // check if the new and old source are dummy
397    sp<MediaSource> anAudioSource = mAudioPlayer->getSource();
398    if (anAudioSource == NULL) {
399        // Audio player does not have any source set.
400        ALOGV("setAudioPlayer: Audio player does not have any source set");
401        return OK;
402    }
403
404    // If new video source is not dummy, then always change source
405    // Else audio player continues using old audio source and there are
406    // frame drops to maintain AV sync
407    sp<MetaData> meta;
408    if (mVideoSource != NULL) {
409        meta = mVideoSource->getFormat();
410        const char *pVidSrcType;
411        if (meta->findCString(kKeyDecoderComponent, &pVidSrcType)) {
412            if (strcmp(pVidSrcType, "DummyVideoSource") != 0) {
413                ALOGV(" Video clip with silent audio; need to change source");
414                return OK;
415            }
416        }
417    }
418
419    const char *pSrcType1;
420    const char *pSrcType2;
421    meta = anAudioSource->getFormat();
422
423    if (meta->findCString(kKeyDecoderComponent, &pSrcType1)) {
424        if (strcmp(pSrcType1, "DummyAudioSource") == 0) {
425            meta = mAudioSource->getFormat();
426            if (meta->findCString(kKeyDecoderComponent, &pSrcType2)) {
427                if (strcmp(pSrcType2, "DummyAudioSource") == 0) {
428                    mIsChangeSourceRequired = false;
429                    // Just set the new play duration for the existing source
430                    MediaSource *pMediaSrc = anAudioSource.get();
431                    DummyAudioSource *pDummyAudioSource = (DummyAudioSource*)pMediaSrc;
432                    //Increment the duration of audio source
433                    pDummyAudioSource->setDuration(
434                        (int64_t)((mPlayEndTimeMsec)*1000LL));
435
436                    // Stop the new audio source
437                    // since we continue using old source
438                    ALOGV("setAudioPlayer: stop new audio source");
439                    mAudioSource->stop();
440                }
441            }
442        }
443    }
444
445    return OK;
446}
447
448void PreviewPlayer::onStreamDone() {
449    ALOGV("onStreamDone");
450    // Posted whenever any stream finishes playing.
451
452    Mutex::Autolock autoLock(mLock);
453    if (!mStreamDoneEventPending) {
454        return;
455    }
456    mStreamDoneEventPending = false;
457
458    if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
459        ALOGV("MEDIA_ERROR %d", mStreamDoneStatus);
460
461        notifyListener_l(
462                MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
463
464        pause_l(true /* at eos */);
465
466        mFlags |= AT_EOS;
467        return;
468    }
469
470    const bool allDone =
471        (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
472            && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
473
474    if (!allDone) {
475        return;
476    }
477
478    if (mFlags & (LOOPING | AUTO_LOOPING)) {
479        seekTo_l(0);
480
481        if (mVideoSource != NULL) {
482            postVideoEvent_l();
483        }
484    } else {
485        ALOGV("MEDIA_PLAYBACK_COMPLETE");
486        //pause before sending event
487        pause_l(true /* at eos */);
488
489        //This lock is used to syncronize onStreamDone() in PreviewPlayer and
490        //stopPreview() in PreviewController
491        Mutex::Autolock autoLock(mLockControl);
492        /* Make sure PreviewPlayer only notifies MEDIA_PLAYBACK_COMPLETE once for each clip!
493         * It happens twice in following scenario.
494         * To make the clips in preview storyboard are played and switched smoothly,
495         * PreviewController uses two PreviewPlayer instances and one AudioPlayer.
496         * The two PreviewPlayer use the same AudioPlayer to play the audio,
497         * and change the audio source of the AudioPlayer.
498         * If the audio source of current playing clip and next clip are dummy
499         * audio source(image or video without audio), it will not change the audio source
500         * to avoid the "audio glitch", and keep using the current audio source.
501         * When the video of current clip reached the EOS, PreviewPlayer will set EOS flag
502         * for video and audio, and it will notify MEDIA_PLAYBACK_COMPLETE.
503         * But the audio(dummy audio source) is still playing(for next clip),
504         * and when it reached the EOS, and video reached EOS,
505         * PreviewPlayer will notify MEDIA_PLAYBACK_COMPLETE again. */
506        if (!(mFlags & INFORMED_AV_EOS)) {
507            notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
508            mFlags |= INFORMED_AV_EOS;
509        }
510        mFlags |= AT_EOS;
511        ALOGV("onStreamDone end");
512        return;
513    }
514}
515
516
517status_t PreviewPlayer::play_l() {
518    ALOGV("play_l");
519
520    mFlags &= ~SEEK_PREVIEW;
521
522    if (mFlags & PLAYING) {
523        return OK;
524    }
525    mStartNextPlayer = false;
526
527    if (!(mFlags & PREPARED)) {
528        status_t err = prepare_l();
529
530        if (err != OK) {
531            return err;
532        }
533    }
534
535    mFlags |= PLAYING;
536    mFlags |= FIRST_FRAME;
537
538    bool deferredAudioSeek = false;
539
540    if (mAudioSource != NULL) {
541        if (mAudioPlayer == NULL) {
542            if (mAudioSink != NULL) {
543
544                mAudioPlayer = new VideoEditorAudioPlayer(mAudioSink, this);
545                mAudioPlayer->setSource(mAudioSource);
546
547                mAudioPlayer->setAudioMixSettings(
548                 mPreviewPlayerAudioMixSettings);
549
550                mAudioPlayer->setAudioMixPCMFileHandle(
551                 mAudioMixPCMFileHandle);
552
553                mAudioPlayer->setAudioMixStoryBoardSkimTimeStamp(
554                 mAudioMixStoryBoardTS, mCurrentMediaBeginCutTime,
555                 mCurrentMediaVolumeValue);
556
557                 mFlags |= AUDIOPLAYER_STARTED;
558                // We've already started the MediaSource in order to enable
559                // the prefetcher to read its data.
560                status_t err = mAudioPlayer->start(
561                        true /* sourceAlreadyStarted */);
562
563                if (err != OK) {
564                    //delete mAudioPlayer;
565                    mAudioPlayer = NULL;
566
567                    mFlags &= ~(PLAYING | FIRST_FRAME);
568                    return err;
569                }
570
571                mTimeSource = mAudioPlayer;
572                mFlags |= AUDIO_RUNNING;
573                deferredAudioSeek = true;
574                mWatchForAudioSeekComplete = false;
575                mWatchForAudioEOS = true;
576            }
577        } else {
578            bool isAudioPlayerStarted = mAudioPlayer->isStarted();
579
580            if (mIsChangeSourceRequired == true) {
581                ALOGV("play_l: Change audio source required");
582
583                if (isAudioPlayerStarted == true) {
584                    mAudioPlayer->pause();
585                }
586
587                mAudioPlayer->setSource(mAudioSource);
588                mAudioPlayer->setObserver(this);
589
590                mAudioPlayer->setAudioMixSettings(
591                 mPreviewPlayerAudioMixSettings);
592
593                mAudioPlayer->setAudioMixStoryBoardSkimTimeStamp(
594                    mAudioMixStoryBoardTS, mCurrentMediaBeginCutTime,
595                    mCurrentMediaVolumeValue);
596
597                if (isAudioPlayerStarted == true) {
598                    mAudioPlayer->resume();
599                } else {
600                    status_t err = OK;
601                    err = mAudioPlayer->start(true);
602                    if (err != OK) {
603                        mAudioPlayer = NULL;
604                        mAudioPlayer = NULL;
605
606                        mFlags &= ~(PLAYING | FIRST_FRAME);
607                        return err;
608                    }
609                }
610            } else {
611                ALOGV("play_l: No Source change required");
612                mAudioPlayer->setAudioMixStoryBoardSkimTimeStamp(
613                    mAudioMixStoryBoardTS, mCurrentMediaBeginCutTime,
614                    mCurrentMediaVolumeValue);
615
616                mAudioPlayer->resume();
617            }
618
619            mFlags |= AUDIOPLAYER_STARTED;
620            mFlags |= AUDIO_RUNNING;
621            mTimeSource = mAudioPlayer;
622            deferredAudioSeek = true;
623            mWatchForAudioSeekComplete = false;
624            mWatchForAudioEOS = true;
625        }
626    }
627
628    if (mTimeSource == NULL && mAudioPlayer == NULL) {
629        mTimeSource = &mSystemTimeSource;
630    }
631
632    // Set the seek option for Image source files and read.
633    // This resets the timestamping for image play
634    if (mIsVideoSourceJpg) {
635        MediaSource::ReadOptions options;
636        MediaBuffer *aLocalBuffer;
637        options.setSeekTo(mSeekTimeUs);
638        mVideoSource->read(&aLocalBuffer, &options);
639        aLocalBuffer->release();
640    }
641
642    if (mVideoSource != NULL) {
643        // Kick off video playback
644        postVideoEvent_l();
645    }
646
647    if (deferredAudioSeek) {
648        // If there was a seek request while we were paused
649        // and we're just starting up again, honor the request now.
650        seekAudioIfNecessary_l();
651    }
652
653    if (mFlags & AT_EOS) {
654        // Legacy behaviour, if a stream finishes playing and then
655        // is started again, we play from the start...
656        seekTo_l(0);
657    }
658
659    return OK;
660}
661
662
663status_t PreviewPlayer::initRenderer_l() {
664    if (mSurface != NULL) {
665        if(mVideoRenderer == NULL) {
666            mVideoRenderer = mNativeWindowRenderer->createRenderInput();
667            if (mVideoSource != NULL) {
668                updateSizeToRender(mVideoSource->getFormat());
669            }
670        }
671    }
672    return OK;
673}
674
675
676status_t PreviewPlayer::seekTo(int64_t timeUs) {
677    Mutex::Autolock autoLock(mLock);
678    if ((mExtractorFlags & MediaExtractor::CAN_SEEK) || (mIsVideoSourceJpg)) {
679        return seekTo_l(timeUs);
680    }
681
682    return OK;
683}
684
685
686status_t PreviewPlayer::getVideoDimensions(
687        int32_t *width, int32_t *height) const {
688    Mutex::Autolock autoLock(mLock);
689
690    if (mVideoWidth < 0 || mVideoHeight < 0) {
691        return UNKNOWN_ERROR;
692    }
693
694    *width = mVideoWidth;
695    *height = mVideoHeight;
696
697    return OK;
698}
699
700
701status_t PreviewPlayer::initAudioDecoder_l() {
702    sp<MetaData> meta = mAudioTrack->getFormat();
703    const char *mime;
704    CHECK(meta->findCString(kKeyMIMEType, &mime));
705
706    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
707        mAudioSource = mAudioTrack;
708    } else {
709        sp<MediaSource> aRawSource;
710        aRawSource = OMXCodec::Create(
711                mClient.interface(), mAudioTrack->getFormat(),
712                false, // createEncoder
713                mAudioTrack);
714
715        if(aRawSource != NULL) {
716            mAudioSource = new VideoEditorSRC(aRawSource);
717        }
718    }
719
720    if (mAudioSource != NULL) {
721        int64_t durationUs;
722        if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
723            setDuration_l(durationUs);
724        }
725        status_t err = mAudioSource->start();
726
727        if (err != OK) {
728            mAudioSource.clear();
729            return err;
730        }
731    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
732        // For legacy reasons we're simply going to ignore the absence
733        // of an audio decoder for QCELP instead of aborting playback
734        // altogether.
735        return OK;
736    }
737
738    return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
739}
740
741status_t PreviewPlayer::initVideoDecoder_l(uint32_t flags) {
742    initRenderer_l();
743
744    if (mVideoRenderer == NULL) {
745        ALOGE("Cannot create renderer");
746        return UNKNOWN_ERROR;
747    }
748
749    mVideoSource = OMXCodec::Create(
750            mClient.interface(), mVideoTrack->getFormat(),
751            false,
752            mVideoTrack,
753            NULL, flags, mVideoRenderer->getTargetWindow());
754
755    if (mVideoSource != NULL) {
756        int64_t durationUs;
757        if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
758            setDuration_l(durationUs);
759        }
760
761        updateSizeToRender(mVideoTrack->getFormat());
762
763        status_t err = mVideoSource->start();
764
765        if (err != OK) {
766            mVideoSource.clear();
767            return err;
768        }
769    }
770
771    return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
772}
773
774
775void PreviewPlayer::onVideoEvent() {
776    uint32_t i=0;
777    M4OSA_ERR err1 = M4NO_ERROR;
778    int64_t imageFrameTimeUs = 0;
779
780    Mutex::Autolock autoLock(mLock);
781    if (!mVideoEventPending) {
782        // The event has been cancelled in reset_l() but had already
783        // been scheduled for execution at that time.
784        return;
785    }
786    mVideoEventPending = false;
787
788    if (mFlags & SEEK_PREVIEW) {
789        mFlags &= ~SEEK_PREVIEW;
790        return;
791    }
792
793    TimeSource *ts_st =  &mSystemTimeSource;
794    int64_t timeStartUs = ts_st->getRealTimeUs();
795
796    if (mSeeking != NO_SEEK) {
797
798        if(mAudioSource != NULL) {
799
800            // We're going to seek the video source first, followed by
801            // the audio source.
802            // In order to avoid jumps in the DataSource offset caused by
803            // the audio codec prefetching data from the old locations
804            // while the video codec is already reading data from the new
805            // locations, we'll "pause" the audio source, causing it to
806            // stop reading input data until a subsequent seek.
807
808            if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
809                mAudioPlayer->pause();
810                mFlags &= ~AUDIO_RUNNING;
811            }
812            mAudioSource->pause();
813        }
814    }
815
816    if (!mVideoBuffer) {
817        MediaSource::ReadOptions options;
818        if (mSeeking != NO_SEEK) {
819            ALOGV("LV PLAYER seeking to %lld us (%.2f secs)", mSeekTimeUs,
820                                                      mSeekTimeUs / 1E6);
821
822            options.setSeekTo(
823                    mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST);
824        }
825        for (;;) {
826            status_t err = mVideoSource->read(&mVideoBuffer, &options);
827            options.clearSeekTo();
828
829            if (err != OK) {
830                CHECK(!mVideoBuffer);
831
832                if (err == INFO_FORMAT_CHANGED) {
833                    ALOGV("LV PLAYER VideoSource signalled format change");
834                    notifyVideoSize_l();
835
836                    if (mVideoRenderer != NULL) {
837                        mVideoRendererIsPreview = false;
838                        err = initRenderer_l();
839                        if (err != OK) {
840                            postStreamDoneEvent_l(err);
841                        }
842
843                    }
844
845                    updateSizeToRender(mVideoSource->getFormat());
846                    continue;
847                }
848                // So video playback is complete, but we may still have
849                // a seek request pending that needs to be applied to the audio track
850                if (mSeeking != NO_SEEK) {
851                    ALOGV("video stream ended while seeking!");
852                }
853                finishSeekIfNecessary(-1);
854                ALOGV("PreviewPlayer: onVideoEvent EOS reached.");
855                mFlags |= VIDEO_AT_EOS;
856                mFlags |= AUDIO_AT_EOS;
857                mOverlayUpdateEventPosted = false;
858                postStreamDoneEvent_l(err);
859                // Set the last decoded timestamp to duration
860                mDecodedVideoTs = (mPlayEndTimeMsec*1000LL);
861                return;
862            }
863
864            if (mVideoBuffer->range_length() == 0) {
865                // Some decoders, notably the PV AVC software decoder
866                // return spurious empty buffers that we just want to ignore.
867
868                mVideoBuffer->release();
869                mVideoBuffer = NULL;
870                continue;
871            }
872
873            int64_t videoTimeUs;
874            CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &videoTimeUs));
875
876            if (mSeeking != NO_SEEK) {
877                if (videoTimeUs < mSeekTimeUs) {
878                    // buffers are before seek time
879                    // ignore them
880                    mVideoBuffer->release();
881                    mVideoBuffer = NULL;
882                    continue;
883                }
884            } else {
885                if((videoTimeUs/1000) < mPlayBeginTimeMsec) {
886                    // Frames are before begin cut time
887                    // Donot render
888                    mVideoBuffer->release();
889                    mVideoBuffer = NULL;
890                    continue;
891                }
892            }
893            break;
894        }
895    }
896
897    mNumberDecVideoFrames++;
898
899    int64_t timeUs;
900    CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
901    setPosition_l(timeUs);
902
903    if (!mStartNextPlayer) {
904        int64_t playbackTimeRemaining = (mPlayEndTimeMsec * 1000LL) - timeUs;
905        if (playbackTimeRemaining <= 1500000) {
906            //When less than 1.5 sec of playback left
907            // send notification to start next player
908
909            mStartNextPlayer = true;
910            notifyListener_l(0xAAAAAAAA);
911        }
912    }
913
914    SeekType wasSeeking = mSeeking;
915    finishSeekIfNecessary(timeUs);
916    if (mAudioPlayer != NULL && !(mFlags & (AUDIO_RUNNING))) {
917        status_t err = startAudioPlayer_l();
918        if (err != OK) {
919            ALOGE("Starting the audio player failed w/ err %d", err);
920            return;
921        }
922    }
923
924    TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
925
926    if(ts == NULL) {
927        mVideoBuffer->release();
928        mVideoBuffer = NULL;
929        return;
930    }
931
932    if(!mIsVideoSourceJpg) {
933        if (mFlags & FIRST_FRAME) {
934            mFlags &= ~FIRST_FRAME;
935
936            mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
937        }
938
939        int64_t realTimeUs, mediaTimeUs;
940        if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
941            && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
942            mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
943        }
944
945        int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
946
947        int64_t latenessUs = nowUs - timeUs;
948
949        if (wasSeeking != NO_SEEK) {
950            // Let's display the first frame after seeking right away.
951            latenessUs = 0;
952        }
953        ALOGV("Audio time stamp = %lld and video time stamp = %lld",
954                                            ts->getRealTimeUs(),timeUs);
955        if (latenessUs > 40000) {
956            // We're more than 40ms late.
957
958            ALOGV("LV PLAYER we're late by %lld us (%.2f secs)",
959                                           latenessUs, latenessUs / 1E6);
960
961            mVideoBuffer->release();
962            mVideoBuffer = NULL;
963            postVideoEvent_l(0);
964            return;
965        }
966
967        if (latenessUs < -25000) {
968            // We're more than 25ms early.
969            ALOGV("We're more than 25ms early, lateness %lld", latenessUs);
970
971            postVideoEvent_l(25000);
972            return;
973        }
974    }
975
976    if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
977        mVideoRendererIsPreview = false;
978
979        status_t err = initRenderer_l();
980        if (err != OK) {
981            postStreamDoneEvent_l(err);
982        }
983    }
984
985    // If timestamp exceeds endCutTime of clip, donot render
986    if((timeUs/1000) > mPlayEndTimeMsec) {
987        mVideoBuffer->release();
988        mVideoBuffer = NULL;
989        mFlags |= VIDEO_AT_EOS;
990        mFlags |= AUDIO_AT_EOS;
991        ALOGV("PreviewPlayer: onVideoEvent timeUs > mPlayEndTime; send EOS..");
992        mOverlayUpdateEventPosted = false;
993        // Set the last decoded timestamp to duration
994        mDecodedVideoTs = (mPlayEndTimeMsec*1000LL);
995        postStreamDoneEvent_l(ERROR_END_OF_STREAM);
996        return;
997    }
998    // Capture the frame timestamp to be rendered
999    mDecodedVideoTs = timeUs;
1000
1001    // Post processing to apply video effects
1002    for(i=0;i<mNumberEffects;i++) {
1003        // First check if effect starttime matches the clip being previewed
1004        if((mEffectsSettings[i].uiStartTime < (mDecVideoTsStoryBoard/1000)) ||
1005        (mEffectsSettings[i].uiStartTime >=
1006         ((mDecVideoTsStoryBoard/1000) + mPlayEndTimeMsec - mPlayBeginTimeMsec)))
1007        {
1008            // This effect doesn't belong to this clip, check next one
1009            continue;
1010        }
1011        // Check if effect applies to this particular frame timestamp
1012        if((mEffectsSettings[i].uiStartTime <=
1013         (((timeUs+mDecVideoTsStoryBoard)/1000)-mPlayBeginTimeMsec)) &&
1014            ((mEffectsSettings[i].uiStartTime+mEffectsSettings[i].uiDuration) >=
1015             (((timeUs+mDecVideoTsStoryBoard)/1000)-mPlayBeginTimeMsec))
1016              && (mEffectsSettings[i].uiDuration != 0)) {
1017            setVideoPostProcessingNode(
1018             mEffectsSettings[i].VideoEffectType, TRUE);
1019        }
1020        else {
1021            setVideoPostProcessingNode(
1022             mEffectsSettings[i].VideoEffectType, FALSE);
1023        }
1024    }
1025
1026    //Provide the overlay Update indication when there is an overlay effect
1027    if (mCurrentVideoEffect & VIDEO_EFFECT_FRAMING) {
1028        mCurrentVideoEffect &= ~VIDEO_EFFECT_FRAMING; //never apply framing here.
1029        if (!mOverlayUpdateEventPosted) {
1030            // Find the effect in effectSettings array
1031            M4OSA_UInt32 index;
1032            for (index = 0; index < mNumberEffects; index++) {
1033                M4OSA_UInt32 timeMs = mDecodedVideoTs/1000;
1034                M4OSA_UInt32 timeOffset = mDecVideoTsStoryBoard/1000;
1035                if(mEffectsSettings[index].VideoEffectType ==
1036                    (M4VSS3GPP_VideoEffectType)M4xVSS_kVideoEffectType_Framing) {
1037                    if (((mEffectsSettings[index].uiStartTime + 1) <=
1038                        timeMs + timeOffset - mPlayBeginTimeMsec) &&
1039                        ((mEffectsSettings[index].uiStartTime - 1 +
1040                        mEffectsSettings[index].uiDuration) >=
1041                        timeMs + timeOffset - mPlayBeginTimeMsec))
1042                    {
1043                        break;
1044                    }
1045                }
1046            }
1047            if (index < mNumberEffects) {
1048                mCurrFramingEffectIndex = index;
1049                mOverlayUpdateEventPosted = true;
1050                postOverlayUpdateEvent_l();
1051                ALOGV("Framing index = %ld", mCurrFramingEffectIndex);
1052            } else {
1053                ALOGV("No framing effects found");
1054            }
1055        }
1056
1057    } else if (mOverlayUpdateEventPosted) {
1058        //Post the event when the overlay is no more valid
1059        ALOGV("Overlay is Done");
1060        mOverlayUpdateEventPosted = false;
1061        postOverlayUpdateEvent_l();
1062    }
1063
1064    if (mVideoRenderer != NULL) {
1065        mVideoRenderer->render(mVideoBuffer, mCurrentVideoEffect,
1066                mRenderingMode, mIsVideoSourceJpg);
1067    }
1068
1069    mVideoBuffer->release();
1070    mVideoBuffer = NULL;
1071
1072    // Post progress callback based on callback interval set
1073    if(mNumberDecVideoFrames >= mProgressCbInterval) {
1074        postProgressCallbackEvent_l();
1075        mNumberDecVideoFrames = 0;  // reset counter
1076    }
1077
1078    // if reached EndCutTime of clip, post EOS event
1079    if((timeUs/1000) >= mPlayEndTimeMsec) {
1080        ALOGV("PreviewPlayer: onVideoEvent EOS.");
1081        mFlags |= VIDEO_AT_EOS;
1082        mFlags |= AUDIO_AT_EOS;
1083        mOverlayUpdateEventPosted = false;
1084        // Set the last decoded timestamp to duration
1085        mDecodedVideoTs = (mPlayEndTimeMsec*1000LL);
1086        postStreamDoneEvent_l(ERROR_END_OF_STREAM);
1087    }
1088    else {
1089        if ((wasSeeking != NO_SEEK) && (mFlags & SEEK_PREVIEW)) {
1090            mFlags &= ~SEEK_PREVIEW;
1091            return;
1092        }
1093
1094        if(!mIsVideoSourceJpg) {
1095            postVideoEvent_l(0);
1096        }
1097        else {
1098            postVideoEvent_l(33000);
1099        }
1100    }
1101}
1102
1103status_t PreviewPlayer::prepare() {
1104    ALOGV("prepare");
1105    Mutex::Autolock autoLock(mLock);
1106    return prepare_l();
1107}
1108
1109status_t PreviewPlayer::prepare_l() {
1110    ALOGV("prepare_l");
1111    if (mFlags & PREPARED) {
1112        return OK;
1113    }
1114
1115    if (mFlags & PREPARING) {
1116        return UNKNOWN_ERROR;
1117    }
1118
1119    mIsAsyncPrepare = false;
1120    status_t err = prepareAsync_l();
1121
1122    if (err != OK) {
1123        return err;
1124    }
1125
1126    while (mFlags & PREPARING) {
1127        mPreparedCondition.wait(mLock);
1128    }
1129
1130    return mPrepareResult;
1131}
1132
1133status_t PreviewPlayer::prepareAsync() {
1134    ALOGV("prepareAsync");
1135    Mutex::Autolock autoLock(mLock);
1136    return prepareAsync_l();
1137}
1138
1139status_t PreviewPlayer::prepareAsync_l() {
1140    ALOGV("prepareAsync_l");
1141    if (mFlags & PREPARING) {
1142        return UNKNOWN_ERROR;  // async prepare already pending
1143    }
1144
1145    if (!mQueueStarted) {
1146        mQueue.start();
1147        mQueueStarted = true;
1148    }
1149
1150    mFlags |= PREPARING;
1151    mAsyncPrepareEvent = new PreviewPlayerEvent(
1152            this, &PreviewPlayer::onPrepareAsyncEvent);
1153
1154    mQueue.postEvent(mAsyncPrepareEvent);
1155
1156    return OK;
1157}
1158
1159status_t PreviewPlayer::finishSetDataSource_l() {
1160    sp<DataSource> dataSource;
1161    sp<MediaExtractor> extractor;
1162
1163    dataSource = DataSource::CreateFromURI(mUri.string(), NULL);
1164
1165    if (dataSource == NULL) {
1166        return UNKNOWN_ERROR;
1167    }
1168
1169    //If file type is .rgb, then no need to check for Extractor
1170    int uriLen = strlen(mUri);
1171    int startOffset = uriLen - 4;
1172    if(!strncasecmp(mUri+startOffset, ".rgb", 4)) {
1173        extractor = NULL;
1174    }
1175    else {
1176        extractor = MediaExtractor::Create(dataSource,
1177                                        MEDIA_MIMETYPE_CONTAINER_MPEG4);
1178    }
1179
1180    if (extractor == NULL) {
1181        ALOGV("finishSetDataSource_l: failed to create extractor");
1182        return setDataSource_l_jpg();
1183    }
1184
1185    return setDataSource_l(extractor);
1186}
1187
1188void PreviewPlayer::onPrepareAsyncEvent() {
1189    Mutex::Autolock autoLock(mLock);
1190    ALOGV("onPrepareAsyncEvent");
1191
1192    if (mFlags & PREPARE_CANCELLED) {
1193        ALOGV("prepare was cancelled before doing anything");
1194        abortPrepare(UNKNOWN_ERROR);
1195        return;
1196    }
1197
1198    if (mUri.size() > 0) {
1199        status_t err = finishSetDataSource_l();
1200
1201        if (err != OK) {
1202            abortPrepare(err);
1203            return;
1204        }
1205    }
1206
1207    if (mVideoTrack != NULL && mVideoSource == NULL) {
1208        status_t err = initVideoDecoder_l(OMXCodec::kHardwareCodecsOnly);
1209
1210        if (err != OK) {
1211            abortPrepare(err);
1212            return;
1213        }
1214    }
1215
1216    if (mAudioTrack != NULL && mAudioSource == NULL) {
1217        status_t err = initAudioDecoder_l();
1218
1219        if (err != OK) {
1220            abortPrepare(err);
1221            return;
1222        }
1223    }
1224    finishAsyncPrepare_l();
1225
1226}
1227
1228void PreviewPlayer::finishAsyncPrepare_l() {
1229    ALOGV("finishAsyncPrepare_l");
1230    if (mIsAsyncPrepare) {
1231        if (mVideoSource == NULL) {
1232            notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1233        } else {
1234            notifyVideoSize_l();
1235        }
1236        notifyListener_l(MEDIA_PREPARED);
1237    }
1238
1239    mPrepareResult = OK;
1240    mFlags &= ~(PREPARING|PREPARE_CANCELLED);
1241    mFlags |= PREPARED;
1242    mAsyncPrepareEvent = NULL;
1243    mPreparedCondition.broadcast();
1244}
1245
1246void PreviewPlayer::acquireLock() {
1247    ALOGV("acquireLock");
1248    mLockControl.lock();
1249}
1250
1251void PreviewPlayer::releaseLock() {
1252    ALOGV("releaseLock");
1253    mLockControl.unlock();
1254}
1255
1256status_t PreviewPlayer::loadEffectsSettings(
1257        M4VSS3GPP_EffectSettings* pEffectSettings, int nEffects) {
1258
1259    ALOGV("loadEffectsSettings");
1260    mNumberEffects = nEffects;
1261    mEffectsSettings = pEffectSettings;
1262    return OK;
1263}
1264
1265status_t PreviewPlayer::loadAudioMixSettings(
1266        M4xVSS_AudioMixingSettings* pAudioMixSettings) {
1267
1268    ALOGV("loadAudioMixSettings");
1269    mPreviewPlayerAudioMixSettings = pAudioMixSettings;
1270    return OK;
1271}
1272
1273status_t PreviewPlayer::setAudioMixPCMFileHandle(
1274        M4OSA_Context pAudioMixPCMFileHandle) {
1275
1276    ALOGV("setAudioMixPCMFileHandle");
1277    mAudioMixPCMFileHandle = pAudioMixPCMFileHandle;
1278    return OK;
1279}
1280
1281status_t PreviewPlayer::setAudioMixStoryBoardParam(
1282        M4OSA_UInt32 audioMixStoryBoardTS,
1283        M4OSA_UInt32 currentMediaBeginCutTime,
1284        M4OSA_UInt32 primaryTrackVolValue ) {
1285
1286    ALOGV("setAudioMixStoryBoardParam");
1287    mAudioMixStoryBoardTS = audioMixStoryBoardTS;
1288    mCurrentMediaBeginCutTime = currentMediaBeginCutTime;
1289    mCurrentMediaVolumeValue = primaryTrackVolValue;
1290    return OK;
1291}
1292
1293status_t PreviewPlayer::setPlaybackBeginTime(uint32_t msec) {
1294
1295    mPlayBeginTimeMsec = msec;
1296    return OK;
1297}
1298
1299status_t PreviewPlayer::setPlaybackEndTime(uint32_t msec) {
1300
1301    mPlayEndTimeMsec = msec;
1302    return OK;
1303}
1304
1305status_t PreviewPlayer::setStoryboardStartTime(uint32_t msec) {
1306
1307    mStoryboardStartTimeMsec = msec;
1308    mDecVideoTsStoryBoard = mStoryboardStartTimeMsec * 1000LL;
1309    return OK;
1310}
1311
1312status_t PreviewPlayer::setProgressCallbackInterval(uint32_t cbInterval) {
1313
1314    mProgressCbInterval = cbInterval;
1315    return OK;
1316}
1317
1318
1319status_t PreviewPlayer::setMediaRenderingMode(
1320        M4xVSS_MediaRendering mode,
1321        M4VIDEOEDITING_VideoFrameSize outputVideoSize) {
1322
1323    mRenderingMode = mode;
1324
1325    /* get the video width and height by resolution */
1326    return getVideoSizeByResolution(
1327                outputVideoSize,
1328                    &mOutputVideoWidth, &mOutputVideoHeight);
1329
1330}
1331
1332status_t PreviewPlayer::resetJniCallbackTimeStamp() {
1333
1334    mDecVideoTsStoryBoard = mStoryboardStartTimeMsec * 1000LL;
1335    return OK;
1336}
1337
1338void PreviewPlayer::postProgressCallbackEvent_l() {
1339    if (mProgressCbEventPending) {
1340        return;
1341    }
1342    mProgressCbEventPending = true;
1343
1344    mQueue.postEvent(mProgressCbEvent);
1345}
1346
1347
1348void PreviewPlayer::onProgressCbEvent() {
1349    Mutex::Autolock autoLock(mLock);
1350    if (!mProgressCbEventPending) {
1351        return;
1352    }
1353    mProgressCbEventPending = false;
1354    // If playback starts from previous I-frame,
1355    // then send frame storyboard duration
1356    if ((mDecodedVideoTs/1000) < mPlayBeginTimeMsec) {
1357        notifyListener_l(MEDIA_INFO, 0, mDecVideoTsStoryBoard/1000);
1358    } else {
1359        notifyListener_l(MEDIA_INFO, 0,
1360        (((mDecodedVideoTs+mDecVideoTsStoryBoard)/1000)-mPlayBeginTimeMsec));
1361    }
1362}
1363
1364void PreviewPlayer::postOverlayUpdateEvent_l() {
1365    if (mOverlayUpdateEventPending) {
1366        return;
1367    }
1368    mOverlayUpdateEventPending = true;
1369    mQueue.postEvent(mOverlayUpdateEvent);
1370}
1371
1372void PreviewPlayer::onUpdateOverlayEvent() {
1373    Mutex::Autolock autoLock(mLock);
1374
1375    if (!mOverlayUpdateEventPending) {
1376        return;
1377    }
1378    mOverlayUpdateEventPending = false;
1379
1380    int updateState = mOverlayUpdateEventPosted? 1: 0;
1381    notifyListener_l(0xBBBBBBBB, updateState, mCurrFramingEffectIndex);
1382}
1383
1384
1385void PreviewPlayer::setVideoPostProcessingNode(
1386        M4VSS3GPP_VideoEffectType type, M4OSA_Bool enable) {
1387
1388    uint32_t effect = VIDEO_EFFECT_NONE;
1389
1390    //Map M4VSS3GPP_VideoEffectType to local enum
1391    switch(type) {
1392        case M4VSS3GPP_kVideoEffectType_FadeFromBlack:
1393            effect = VIDEO_EFFECT_FADEFROMBLACK;
1394            break;
1395
1396        case M4VSS3GPP_kVideoEffectType_FadeToBlack:
1397            effect = VIDEO_EFFECT_FADETOBLACK;
1398            break;
1399
1400        case M4xVSS_kVideoEffectType_BlackAndWhite:
1401            effect = VIDEO_EFFECT_BLACKANDWHITE;
1402            break;
1403
1404        case M4xVSS_kVideoEffectType_Pink:
1405            effect = VIDEO_EFFECT_PINK;
1406            break;
1407
1408        case M4xVSS_kVideoEffectType_Green:
1409            effect = VIDEO_EFFECT_GREEN;
1410            break;
1411
1412        case M4xVSS_kVideoEffectType_Sepia:
1413            effect = VIDEO_EFFECT_SEPIA;
1414            break;
1415
1416        case M4xVSS_kVideoEffectType_Negative:
1417            effect = VIDEO_EFFECT_NEGATIVE;
1418            break;
1419
1420        case M4xVSS_kVideoEffectType_Framing:
1421            effect = VIDEO_EFFECT_FRAMING;
1422            break;
1423
1424        case M4xVSS_kVideoEffectType_Fifties:
1425            effect = VIDEO_EFFECT_FIFTIES;
1426            break;
1427
1428        case M4xVSS_kVideoEffectType_ColorRGB16:
1429            effect = VIDEO_EFFECT_COLOR_RGB16;
1430            break;
1431
1432        case M4xVSS_kVideoEffectType_Gradient:
1433            effect = VIDEO_EFFECT_GRADIENT;
1434            break;
1435
1436        default:
1437            effect = VIDEO_EFFECT_NONE;
1438            break;
1439    }
1440
1441    if (enable == M4OSA_TRUE) {
1442        //If already set, then no need to set again
1443        if (!(mCurrentVideoEffect & effect)) {
1444            mCurrentVideoEffect |= effect;
1445            if (effect == VIDEO_EFFECT_FIFTIES) {
1446                mIsFiftiesEffectStarted = true;
1447            }
1448        }
1449    } else  {
1450        //Reset only if already set
1451        if (mCurrentVideoEffect & effect) {
1452            mCurrentVideoEffect &= ~effect;
1453        }
1454    }
1455}
1456
1457status_t PreviewPlayer::setImageClipProperties(uint32_t width,uint32_t height) {
1458    mVideoWidth = width;
1459    mVideoHeight = height;
1460    return OK;
1461}
1462
1463status_t PreviewPlayer::readFirstVideoFrame() {
1464    ALOGV("readFirstVideoFrame");
1465
1466    if (!mVideoBuffer) {
1467        MediaSource::ReadOptions options;
1468        if (mSeeking != NO_SEEK) {
1469            ALOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs,
1470                    mSeekTimeUs / 1E6);
1471
1472            options.setSeekTo(
1473                    mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST);
1474        }
1475        for (;;) {
1476            status_t err = mVideoSource->read(&mVideoBuffer, &options);
1477            options.clearSeekTo();
1478
1479            if (err != OK) {
1480                CHECK(!mVideoBuffer);
1481
1482                if (err == INFO_FORMAT_CHANGED) {
1483                    ALOGV("VideoSource signalled format change");
1484                    notifyVideoSize_l();
1485
1486                    if (mVideoRenderer != NULL) {
1487                        mVideoRendererIsPreview = false;
1488                        err = initRenderer_l();
1489                        if (err != OK) {
1490                            postStreamDoneEvent_l(err);
1491                        }
1492                    }
1493
1494                    updateSizeToRender(mVideoSource->getFormat());
1495                    continue;
1496                }
1497                ALOGV("EOS reached.");
1498                mFlags |= VIDEO_AT_EOS;
1499                mFlags |= AUDIO_AT_EOS;
1500                postStreamDoneEvent_l(err);
1501                return OK;
1502            }
1503
1504            if (mVideoBuffer->range_length() == 0) {
1505                // Some decoders, notably the PV AVC software decoder
1506                // return spurious empty buffers that we just want to ignore.
1507
1508                mVideoBuffer->release();
1509                mVideoBuffer = NULL;
1510                continue;
1511            }
1512
1513            int64_t videoTimeUs;
1514            CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &videoTimeUs));
1515            if (mSeeking != NO_SEEK) {
1516                if (videoTimeUs < mSeekTimeUs) {
1517                    // buffers are before seek time
1518                    // ignore them
1519                    mVideoBuffer->release();
1520                    mVideoBuffer = NULL;
1521                    continue;
1522                }
1523            } else {
1524                if ((videoTimeUs/1000) < mPlayBeginTimeMsec) {
1525                    // buffers are before begin cut time
1526                    // ignore them
1527                    mVideoBuffer->release();
1528                    mVideoBuffer = NULL;
1529                    continue;
1530                }
1531            }
1532            break;
1533        }
1534    }
1535
1536    int64_t timeUs;
1537    CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1538    setPosition_l(timeUs);
1539
1540    mDecodedVideoTs = timeUs;
1541
1542    return OK;
1543
1544}
1545
1546status_t PreviewPlayer::getLastRenderedTimeMs(uint32_t *lastRenderedTimeMs) {
1547    *lastRenderedTimeMs = (((mDecodedVideoTs+mDecVideoTsStoryBoard)/1000)-mPlayBeginTimeMsec);
1548    return OK;
1549}
1550
1551void PreviewPlayer::updateSizeToRender(sp<MetaData> meta) {
1552    if (mVideoRenderer) {
1553        mVideoRenderer->updateVideoSize(meta);
1554    }
1555}
1556
1557void PreviewPlayer::setListener(const wp<MediaPlayerBase> &listener) {
1558    Mutex::Autolock autoLock(mLock);
1559    mListener = listener;
1560}
1561
1562status_t PreviewPlayer::setDataSource(const sp<IStreamSource> &source) {
1563    return INVALID_OPERATION;
1564}
1565
1566void PreviewPlayer::reset() {
1567    Mutex::Autolock autoLock(mLock);
1568    reset_l();
1569}
1570
1571void PreviewPlayer::clear_l() {
1572    mDisplayWidth = 0;
1573    mDisplayHeight = 0;
1574
1575    if (mFlags & PLAYING) {
1576        updateBatteryUsage_l();
1577    }
1578
1579    if (mFlags & PREPARING) {
1580        mFlags |= PREPARE_CANCELLED;
1581
1582        if (mFlags & PREPARING_CONNECTED) {
1583            // We are basically done preparing, we're just buffering
1584            // enough data to start playback, we can safely interrupt that.
1585            finishAsyncPrepare_l();
1586        }
1587    }
1588
1589    while (mFlags & PREPARING) {
1590        mPreparedCondition.wait(mLock);
1591    }
1592
1593    cancelPlayerEvents_l(true);
1594
1595    mAudioTrack.clear();
1596    mVideoTrack.clear();
1597
1598    // Shutdown audio first, so that the respone to the reset request
1599    // appears to happen instantaneously as far as the user is concerned
1600    // If we did this later, audio would continue playing while we
1601    // shutdown the video-related resources and the player appear to
1602    // not be as responsive to a reset request.
1603    if (mAudioPlayer == NULL && mAudioSource != NULL) {
1604        // If we had an audio player, it would have effectively
1605        // taken possession of the audio source and stopped it when
1606        // _it_ is stopped. Otherwise this is still our responsibility.
1607        mAudioSource->stop();
1608    }
1609    mAudioSource.clear();
1610
1611    mTimeSource = NULL;
1612
1613    delete mAudioPlayer;
1614    mAudioPlayer = NULL;
1615
1616    if (mVideoSource != NULL) {
1617        shutdownVideoDecoder_l();
1618    }
1619
1620    mDurationUs = -1;
1621    mFlags = 0;
1622    mExtractorFlags = 0;
1623    mTimeSourceDeltaUs = 0;
1624    mVideoTimeUs = 0;
1625
1626    mSeeking = NO_SEEK;
1627    mSeekNotificationSent = false;
1628    mSeekTimeUs = 0;
1629
1630    mUri.setTo("");
1631
1632    mBitrate = -1;
1633    mLastVideoTimeUs = -1;
1634}
1635
1636void PreviewPlayer::notifyListener_l(int msg, int ext1, int ext2) {
1637    if (mListener != NULL) {
1638        sp<MediaPlayerBase> listener = mListener.promote();
1639
1640        if (listener != NULL) {
1641            listener->sendEvent(msg, ext1, ext2);
1642        }
1643    }
1644}
1645
1646void PreviewPlayer::onVideoLagUpdate() {
1647    Mutex::Autolock autoLock(mLock);
1648    if (!mVideoLagEventPending) {
1649        return;
1650    }
1651    mVideoLagEventPending = false;
1652
1653    int64_t audioTimeUs = mAudioPlayer->getMediaTimeUs();
1654    int64_t videoLateByUs = audioTimeUs - mVideoTimeUs;
1655
1656    if (!(mFlags & VIDEO_AT_EOS) && videoLateByUs > 300000ll) {
1657        ALOGV("video late by %lld ms.", videoLateByUs / 1000ll);
1658
1659        notifyListener_l(
1660                MEDIA_INFO,
1661                MEDIA_INFO_VIDEO_TRACK_LAGGING,
1662                videoLateByUs / 1000ll);
1663    }
1664
1665    postVideoLagEvent_l();
1666}
1667
1668void PreviewPlayer::notifyVideoSize_l() {
1669    sp<MetaData> meta = mVideoSource->getFormat();
1670
1671    int32_t vWidth, vHeight;
1672    int32_t cropLeft, cropTop, cropRight, cropBottom;
1673
1674    CHECK(meta->findInt32(kKeyWidth, &vWidth));
1675    CHECK(meta->findInt32(kKeyHeight, &vHeight));
1676
1677    mGivenWidth = vWidth;
1678    mGivenHeight = vHeight;
1679
1680    if (!meta->findRect(
1681                kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) {
1682
1683        cropLeft = cropTop = 0;
1684        cropRight = vWidth - 1;
1685        cropBottom = vHeight - 1;
1686
1687        ALOGD("got dimensions only %d x %d", vWidth, vHeight);
1688    } else {
1689        ALOGD("got crop rect %d, %d, %d, %d",
1690             cropLeft, cropTop, cropRight, cropBottom);
1691    }
1692
1693    mCropRect.left = cropLeft;
1694    mCropRect.right = cropRight;
1695    mCropRect.top = cropTop;
1696    mCropRect.bottom = cropBottom;
1697
1698    int32_t displayWidth;
1699    if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) {
1700        ALOGV("Display width changed (%d=>%d)", mDisplayWidth, displayWidth);
1701        mDisplayWidth = displayWidth;
1702    }
1703    int32_t displayHeight;
1704    if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) {
1705        ALOGV("Display height changed (%d=>%d)", mDisplayHeight, displayHeight);
1706        mDisplayHeight = displayHeight;
1707    }
1708
1709    int32_t usableWidth = cropRight - cropLeft + 1;
1710    int32_t usableHeight = cropBottom - cropTop + 1;
1711    if (mDisplayWidth != 0) {
1712        usableWidth = mDisplayWidth;
1713    }
1714    if (mDisplayHeight != 0) {
1715        usableHeight = mDisplayHeight;
1716    }
1717
1718    int32_t rotationDegrees;
1719    if (!mVideoTrack->getFormat()->findInt32(
1720                kKeyRotation, &rotationDegrees)) {
1721        rotationDegrees = 0;
1722    }
1723
1724    if (rotationDegrees == 90 || rotationDegrees == 270) {
1725        notifyListener_l(
1726                MEDIA_SET_VIDEO_SIZE, usableHeight, usableWidth);
1727    } else {
1728        notifyListener_l(
1729                MEDIA_SET_VIDEO_SIZE, usableWidth, usableHeight);
1730    }
1731}
1732
1733status_t PreviewPlayer::pause() {
1734    Mutex::Autolock autoLock(mLock);
1735
1736    mFlags &= ~CACHE_UNDERRUN;
1737
1738    return pause_l();
1739}
1740
1741status_t PreviewPlayer::pause_l(bool at_eos) {
1742    if (!(mFlags & PLAYING)) {
1743        return OK;
1744    }
1745
1746    cancelPlayerEvents_l();
1747
1748    if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
1749        if (at_eos) {
1750            // If we played the audio stream to completion we
1751            // want to make sure that all samples remaining in the audio
1752            // track's queue are played out.
1753            mAudioPlayer->pause(true /* playPendingSamples */);
1754        } else {
1755            mAudioPlayer->pause();
1756        }
1757
1758        mFlags &= ~AUDIO_RUNNING;
1759    }
1760
1761    mFlags &= ~PLAYING;
1762    updateBatteryUsage_l();
1763
1764    return OK;
1765}
1766
1767bool PreviewPlayer::isPlaying() const {
1768    return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
1769}
1770
1771void PreviewPlayer::setSurface(const sp<Surface> &surface) {
1772    Mutex::Autolock autoLock(mLock);
1773
1774    mSurface = surface;
1775    setNativeWindow_l(surface);
1776}
1777
1778void PreviewPlayer::setSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {
1779    Mutex::Autolock autoLock(mLock);
1780
1781    mSurface.clear();
1782    if (surfaceTexture != NULL) {
1783        setNativeWindow_l(new SurfaceTextureClient(surfaceTexture));
1784    }
1785}
1786
1787void PreviewPlayer::shutdownVideoDecoder_l() {
1788    if (mVideoBuffer) {
1789        mVideoBuffer->release();
1790        mVideoBuffer = NULL;
1791    }
1792
1793    mVideoSource->stop();
1794
1795    // The following hack is necessary to ensure that the OMX
1796    // component is completely released by the time we may try
1797    // to instantiate it again.
1798    wp<MediaSource> tmp = mVideoSource;
1799    mVideoSource.clear();
1800    while (tmp.promote() != NULL) {
1801        usleep(1000);
1802    }
1803    IPCThreadState::self()->flushCommands();
1804}
1805
1806void PreviewPlayer::setNativeWindow_l(const sp<ANativeWindow> &native) {
1807    mNativeWindow = native;
1808
1809    if (mVideoSource == NULL) {
1810        return;
1811    }
1812
1813    ALOGI("attempting to reconfigure to use new surface");
1814
1815    bool wasPlaying = (mFlags & PLAYING) != 0;
1816
1817    pause_l();
1818
1819    shutdownVideoDecoder_l();
1820
1821    CHECK_EQ(initVideoDecoder_l(), (status_t)OK);
1822
1823    if (mLastVideoTimeUs >= 0) {
1824        mSeeking = SEEK;
1825        mSeekNotificationSent = true;
1826        mSeekTimeUs = mLastVideoTimeUs;
1827        mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
1828    }
1829
1830    if (wasPlaying) {
1831        play_l();
1832    }
1833}
1834
1835void PreviewPlayer::setAudioSink(
1836        const sp<MediaPlayerBase::AudioSink> &audioSink) {
1837    Mutex::Autolock autoLock(mLock);
1838
1839    mAudioSink = audioSink;
1840}
1841
1842status_t PreviewPlayer::setLooping(bool shouldLoop) {
1843    Mutex::Autolock autoLock(mLock);
1844
1845    mFlags = mFlags & ~LOOPING;
1846
1847    if (shouldLoop) {
1848        mFlags |= LOOPING;
1849    }
1850
1851    return OK;
1852}
1853
1854void PreviewPlayer::setDuration_l(int64_t durationUs) {
1855    if (mDurationUs < 0 || durationUs > mDurationUs) {
1856        mDurationUs = durationUs;
1857    }
1858}
1859
1860status_t PreviewPlayer::getDuration(int64_t *durationUs) {
1861    Mutex::Autolock autoLock(mLock);
1862    if (mDurationUs < 0) {
1863        return UNKNOWN_ERROR;
1864    }
1865
1866    *durationUs = mDurationUs;
1867    return OK;
1868}
1869
1870status_t PreviewPlayer::getPosition(int64_t *positionUs) {
1871    Mutex::Autolock autoLock(mLock);
1872
1873    if (mSeeking != NO_SEEK) {
1874        *positionUs = mSeekTimeUs;
1875    } else if (mVideoSource != NULL
1876            && (mAudioPlayer == NULL || !(mFlags & VIDEO_AT_EOS))) {
1877        *positionUs = mVideoTimeUs;
1878    } else if (mAudioPlayer != NULL) {
1879        *positionUs = mAudioPlayer->getMediaTimeUs();
1880    } else {
1881        *positionUs = 0;
1882    }
1883
1884    return OK;
1885}
1886
1887void PreviewPlayer::setPosition_l(int64_t timeUs) {
1888    mVideoTimeUs = timeUs;
1889}
1890
1891status_t PreviewPlayer::seekTo_l(int64_t timeUs) {
1892    ALOGV("seekTo_l");
1893    if (mFlags & CACHE_UNDERRUN) {
1894        mFlags &= ~CACHE_UNDERRUN;
1895        play_l();
1896    }
1897
1898    if ((mFlags & PLAYING) && mVideoSource != NULL && (mFlags & VIDEO_AT_EOS)) {
1899        // Video playback completed before, there's no pending
1900        // video event right now. In order for this new seek
1901        // to be honored, we need to post one.
1902
1903        postVideoEvent_l();
1904    }
1905
1906    mSeeking = SEEK;
1907    mSeekNotificationSent = false;
1908    mSeekTimeUs = timeUs;
1909    mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
1910
1911    seekAudioIfNecessary_l();
1912
1913    if (!(mFlags & PLAYING)) {
1914        ALOGV("seeking while paused, sending SEEK_COMPLETE notification"
1915             " immediately.");
1916
1917        notifyListener_l(MEDIA_SEEK_COMPLETE);
1918        mSeekNotificationSent = true;
1919
1920        if ((mFlags & PREPARED) && mVideoSource != NULL) {
1921            mFlags |= SEEK_PREVIEW;
1922            postVideoEvent_l();
1923        }
1924    }
1925
1926    return OK;
1927}
1928
1929void PreviewPlayer::seekAudioIfNecessary_l() {
1930    if (mSeeking != NO_SEEK && mVideoSource == NULL && mAudioPlayer != NULL) {
1931        mAudioPlayer->seekTo(mSeekTimeUs);
1932
1933        mWatchForAudioSeekComplete = true;
1934        mWatchForAudioEOS = true;
1935    }
1936}
1937
1938void PreviewPlayer::setAudioSource(const sp<MediaSource>& source) {
1939    CHECK(source != NULL);
1940    mAudioTrack = source;
1941}
1942
1943void PreviewPlayer::setVideoSource(const sp<MediaSource>& source) {
1944    CHECK(source != NULL);
1945    mVideoTrack = source;
1946}
1947
1948void PreviewPlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
1949    if (mSeeking == SEEK_VIDEO_ONLY) {
1950        mSeeking = NO_SEEK;
1951        return;
1952    }
1953
1954    if (mSeeking == NO_SEEK || (mFlags & SEEK_PREVIEW)) {
1955        return;
1956    }
1957
1958    if (mAudioPlayer != NULL) {
1959        ALOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6);
1960
1961        // If we don't have a video time, seek audio to the originally
1962        // requested seek time instead.
1963
1964        mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
1965        mWatchForAudioSeekComplete = true;
1966        mWatchForAudioEOS = true;
1967    } else if (!mSeekNotificationSent) {
1968        // If we're playing video only, report seek complete now,
1969        // otherwise audio player will notify us later.
1970        notifyListener_l(MEDIA_SEEK_COMPLETE);
1971        mSeekNotificationSent = true;
1972    }
1973
1974    mFlags |= FIRST_FRAME;
1975    mSeeking = NO_SEEK;
1976}
1977
1978void PreviewPlayer::onCheckAudioStatus() {
1979    Mutex::Autolock autoLock(mLock);
1980    if (!mAudioStatusEventPending) {
1981        // Event was dispatched and while we were blocking on the mutex,
1982        // has already been cancelled.
1983        return;
1984    }
1985
1986    mAudioStatusEventPending = false;
1987
1988    if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1989        mWatchForAudioSeekComplete = false;
1990
1991        if (!mSeekNotificationSent) {
1992            notifyListener_l(MEDIA_SEEK_COMPLETE);
1993            mSeekNotificationSent = true;
1994        }
1995
1996        mSeeking = NO_SEEK;
1997    }
1998
1999    status_t finalStatus;
2000    if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
2001        mWatchForAudioEOS = false;
2002        mFlags |= AUDIO_AT_EOS;
2003        mFlags |= FIRST_FRAME;
2004        postStreamDoneEvent_l(finalStatus);
2005    }
2006}
2007
2008void PreviewPlayer::postVideoEvent_l(int64_t delayUs) {
2009    if (mVideoEventPending) {
2010        return;
2011    }
2012
2013    mVideoEventPending = true;
2014    mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
2015}
2016
2017void PreviewPlayer::postStreamDoneEvent_l(status_t status) {
2018    if (mStreamDoneEventPending) {
2019        return;
2020    }
2021    mStreamDoneEventPending = true;
2022
2023    mStreamDoneStatus = status;
2024    mQueue.postEvent(mStreamDoneEvent);
2025}
2026
2027void PreviewPlayer::postVideoLagEvent_l() {
2028    if (mVideoLagEventPending) {
2029        return;
2030    }
2031    mVideoLagEventPending = true;
2032    mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll);
2033}
2034
2035void PreviewPlayer::postCheckAudioStatusEvent_l(int64_t delayUs) {
2036    if (mAudioStatusEventPending) {
2037        return;
2038    }
2039    mAudioStatusEventPending = true;
2040    mQueue.postEventWithDelay(mCheckAudioStatusEvent, delayUs);
2041}
2042
2043void PreviewPlayer::abortPrepare(status_t err) {
2044    CHECK(err != OK);
2045
2046    if (mIsAsyncPrepare) {
2047        notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
2048    }
2049
2050    mPrepareResult = err;
2051    mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
2052    mAsyncPrepareEvent = NULL;
2053    mPreparedCondition.broadcast();
2054}
2055
2056uint32_t PreviewPlayer::getSourceSeekFlags() const {
2057    Mutex::Autolock lock(mLock);
2058    return mExtractorFlags;
2059}
2060
2061void PreviewPlayer::postAudioEOS(int64_t delayUs) {
2062    Mutex::Autolock autoLock(mLock);
2063    postCheckAudioStatusEvent_l(delayUs);
2064}
2065
2066void PreviewPlayer::postAudioSeekComplete() {
2067    Mutex::Autolock autoLock(mLock);
2068    postCheckAudioStatusEvent_l(0 /* delayUs */);
2069}
2070
2071void PreviewPlayer::updateBatteryUsage_l() {
2072    uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
2073    if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
2074        params |= IMediaPlayerService::kBatteryDataTrackAudio;
2075    }
2076    if (mVideoSource != NULL) {
2077        params |= IMediaPlayerService::kBatteryDataTrackVideo;
2078    }
2079    addBatteryData(params);
2080}
2081
2082}  // namespace android
2083