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             }
     97 
     98             if (err == OK) {
     99                 schedulePull();
    100             }
    101 
    102             sp<AMessage> response = new AMessage;
    103             response->setInt32("err", err);
    104 
    105             uint32_t replyID;
    106             CHECK(msg->senderAwaitsResponse(&replyID));
    107             response->postReply(replyID);
    108             break;
    109         }
    110 
    111         case kWhatStop:
    112         {
    113             sp<MetaData> meta = mSource->getFormat();
    114             const char *tmp;
    115             CHECK(meta->findCString(kKeyMIMEType, &tmp));
    116             AString mime = tmp;
    117 
    118             ALOGI("MediaPuller(%s) stopping.", mime.c_str());
    119             mSource->stop();
    120             ALOGI("MediaPuller(%s) stopped.", mime.c_str());
    121             ++mPullGeneration;
    122 
    123             sp<AMessage> notify;
    124             CHECK(msg->findMessage("notify", &notify));
    125             notify->post();
    126             break;
    127         }
    128 
    129         case kWhatPull:
    130         {
    131             int32_t generation;
    132             CHECK(msg->findInt32("generation", &generation));
    133 
    134             if (generation != mPullGeneration) {
    135                 break;
    136             }
    137 
    138             MediaBuffer *mbuf;
    139             status_t err = mSource->read(&mbuf);
    140 
    141             if (mPaused) {
    142                 if (err == OK) {
    143                     mbuf->release();
    144                     mbuf = NULL;
    145                 }
    146 
    147                 schedulePull();
    148                 break;
    149             }
    150 
    151             if (err != OK) {
    152                 if (err == ERROR_END_OF_STREAM) {
    153                     ALOGI("stream ended.");
    154                 } else {
    155                     ALOGE("error %d reading stream.", err);
    156                 }
    157 
    158                 sp<AMessage> notify = mNotify->dup();
    159                 notify->setInt32("what", kWhatEOS);
    160                 notify->post();
    161             } else {
    162                 int64_t timeUs;
    163                 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
    164 
    165                 sp<ABuffer> accessUnit = new ABuffer(mbuf->range_length());
    166 
    167                 memcpy(accessUnit->data(),
    168                        (const uint8_t *)mbuf->data() + mbuf->range_offset(),
    169                        mbuf->range_length());
    170 
    171                 accessUnit->meta()->setInt64("timeUs", timeUs);
    172 
    173                 if (mIsAudio) {
    174                     mbuf->release();
    175                     mbuf = NULL;
    176                 } else {
    177                     // video encoder will release MediaBuffer when done
    178                     // with underlying data.
    179                     accessUnit->meta()->setPointer("mediaBuffer", mbuf);
    180                 }
    181 
    182                 sp<AMessage> notify = mNotify->dup();
    183 
    184                 notify->setInt32("what", kWhatAccessUnit);
    185                 notify->setBuffer("accessUnit", accessUnit);
    186                 notify->post();
    187 
    188                 if (mbuf != NULL) {
    189                     ALOGV("posted mbuf %p", mbuf);
    190                 }
    191 
    192                 schedulePull();
    193             }
    194             break;
    195         }
    196 
    197         case kWhatPause:
    198         {
    199             mPaused = true;
    200             break;
    201         }
    202 
    203         case kWhatResume:
    204         {
    205             mPaused = false;
    206             break;
    207         }
    208 
    209         default:
    210             TRESPASS();
    211     }
    212 }
    213 
    214 void MediaPuller::schedulePull() {
    215     sp<AMessage> msg = new AMessage(kWhatPull, id());
    216     msg->setInt32("generation", mPullGeneration);
    217     msg->post();
    218 }
    219 
    220 }  // namespace android
    221 
    222