Home | History | Annotate | Download | only in source
      1 /*
      2  * Copyright 2012, 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 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "MediaPuller"
     19 #include <utils/Log.h>
     20 
     21 #include "MediaPuller.h"
     22 
     23 #include <media/stagefright/foundation/ABuffer.h>
     24 #include <media/stagefright/foundation/ADebug.h>
     25 #include <media/stagefright/foundation/AMessage.h>
     26 #include <media/stagefright/MediaBuffer.h>
     27 #include <media/stagefright/MediaSource.h>
     28 #include <media/stagefright/MetaData.h>
     29 
     30 namespace android {
     31 
     32 MediaPuller::MediaPuller(
     33         const sp<MediaSource> &source, const sp<AMessage> &notify)
     34     : mSource(source),
     35       mNotify(notify),
     36       mPullGeneration(0),
     37       mIsAudio(false),
     38       mPaused(false) {
     39     sp<MetaData> meta = source->getFormat();
     40     const char *mime;
     41     CHECK(meta->findCString(kKeyMIMEType, &mime));
     42 
     43     mIsAudio = !strncasecmp(mime, "audio/", 6);
     44 }
     45 
     46 MediaPuller::~MediaPuller() {
     47 }
     48 
     49 status_t MediaPuller::postSynchronouslyAndReturnError(
     50         const sp<AMessage> &msg) {
     51     sp<AMessage> response;
     52     status_t err = msg->postAndAwaitResponse(&response);
     53 
     54     if (err != OK) {
     55         return err;
     56     }
     57 
     58     if (!response->findInt32("err", &err)) {
     59         err = OK;
     60     }
     61 
     62     return err;
     63 }
     64 
     65 status_t MediaPuller::start() {
     66     return postSynchronouslyAndReturnError(new AMessage(kWhatStart, id()));
     67 }
     68 
     69 void MediaPuller::stopAsync(const sp<AMessage> &notify) {
     70     sp<AMessage> msg = new AMessage(kWhatStop, id());
     71     msg->setMessage("notify", notify);
     72     msg->post();
     73 }
     74 
     75 void MediaPuller::pause() {
     76     (new AMessage(kWhatPause, id()))->post();
     77 }
     78 
     79 void MediaPuller::resume() {
     80     (new AMessage(kWhatResume, id()))->post();
     81 }
     82 
     83 void MediaPuller::onMessageReceived(const sp<AMessage> &msg) {
     84     switch (msg->what()) {
     85         case kWhatStart:
     86         {
     87             status_t err;
     88             if (mIsAudio) {
     89                 // This atrocity causes AudioSource to deliver absolute
     90                 // systemTime() based timestamps (off by 1 us).
     91                 sp<MetaData> params = new MetaData;
     92                 params->setInt64(kKeyTime, 1ll);
     93                 err = mSource->start(params.get());
     94             } else {
     95                 err = mSource->start();
     96                 if (err != OK) {
     97                     ALOGE("source failed to start w/ err %d", err);
     98                 }
     99             }
    100 
    101             if (err == OK) {
    102                 schedulePull();
    103             }
    104 
    105             sp<AMessage> response = new AMessage;
    106             response->setInt32("err", err);
    107 
    108             uint32_t replyID;
    109             CHECK(msg->senderAwaitsResponse(&replyID));
    110             response->postReply(replyID);
    111             break;
    112         }
    113 
    114         case kWhatStop:
    115         {
    116             sp<MetaData> meta = mSource->getFormat();
    117             const char *tmp;
    118             CHECK(meta->findCString(kKeyMIMEType, &tmp));
    119             AString mime = tmp;
    120 
    121             ALOGI("MediaPuller(%s) stopping.", mime.c_str());
    122             mSource->stop();
    123             ALOGI("MediaPuller(%s) stopped.", mime.c_str());
    124             ++mPullGeneration;
    125 
    126             sp<AMessage> notify;
    127             CHECK(msg->findMessage("notify", &notify));
    128             notify->post();
    129             break;
    130         }
    131 
    132         case kWhatPull:
    133         {
    134             int32_t generation;
    135             CHECK(msg->findInt32("generation", &generation));
    136 
    137             if (generation != mPullGeneration) {
    138                 break;
    139             }
    140 
    141             MediaBuffer *mbuf;
    142             status_t err = mSource->read(&mbuf);
    143 
    144             if (mPaused) {
    145                 if (err == OK) {
    146                     mbuf->release();
    147                     mbuf = NULL;
    148                 }
    149 
    150                 schedulePull();
    151                 break;
    152             }
    153 
    154             if (err != OK) {
    155                 if (err == ERROR_END_OF_STREAM) {
    156                     ALOGI("stream ended.");
    157                 } else {
    158                     ALOGE("error %d reading stream.", err);
    159                 }
    160 
    161                 sp<AMessage> notify = mNotify->dup();
    162                 notify->setInt32("what", kWhatEOS);
    163                 notify->post();
    164             } else {
    165                 int64_t timeUs;
    166                 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
    167 
    168                 sp<ABuffer> accessUnit = new ABuffer(mbuf->range_length());
    169 
    170                 memcpy(accessUnit->data(),
    171                        (const uint8_t *)mbuf->data() + mbuf->range_offset(),
    172                        mbuf->range_length());
    173 
    174                 accessUnit->meta()->setInt64("timeUs", timeUs);
    175 
    176                 if (mIsAudio) {
    177                     mbuf->release();
    178                     mbuf = NULL;
    179                 } else {
    180                     // video encoder will release MediaBuffer when done
    181                     // with underlying data.
    182                     accessUnit->setMediaBufferBase(mbuf);
    183                 }
    184 
    185                 sp<AMessage> notify = mNotify->dup();
    186 
    187                 notify->setInt32("what", kWhatAccessUnit);
    188                 notify->setBuffer("accessUnit", accessUnit);
    189                 notify->post();
    190 
    191                 if (mbuf != NULL) {
    192                     ALOGV("posted mbuf %p", mbuf);
    193                 }
    194 
    195                 schedulePull();
    196             }
    197             break;
    198         }
    199 
    200         case kWhatPause:
    201         {
    202             mPaused = true;
    203             break;
    204         }
    205 
    206         case kWhatResume:
    207         {
    208             mPaused = false;
    209             break;
    210         }
    211 
    212         default:
    213             TRESPASS();
    214     }
    215 }
    216 
    217 void MediaPuller::schedulePull() {
    218     sp<AMessage> msg = new AMessage(kWhatPull, id());
    219     msg->setInt32("generation", mPullGeneration);
    220     msg->post();
    221 }
    222 
    223 }  // namespace android
    224 
    225