Home | History | Annotate | Download | only in libstagefright
      1 /*
      2  * Copyright (C) 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 "SkipCutBuffer"
     19 #include <utils/Log.h>
     20 
     21 #include <media/stagefright/foundation/ADebug.h>
     22 #include <media/stagefright/MediaBuffer.h>
     23 #include <media/stagefright/SkipCutBuffer.h>
     24 
     25 namespace android {
     26 
     27 SkipCutBuffer::SkipCutBuffer(size_t skip, size_t cut, size_t num16BitChannels) {
     28 
     29     mWriteHead = 0;
     30     mReadHead = 0;
     31     mCapacity = 0;
     32     mCutBuffer = NULL;
     33 
     34     if (num16BitChannels == 0 || num16BitChannels > INT32_MAX / 2) {
     35         ALOGW("# channels out of range: %zu, using passthrough instead", num16BitChannels);
     36         return;
     37     }
     38     size_t frameSize = num16BitChannels * 2;
     39     if (skip > INT32_MAX / frameSize || cut > INT32_MAX / frameSize
     40             || cut * frameSize > INT32_MAX - 4096) {
     41         ALOGW("out of range skip/cut: %zu/%zu, using passthrough instead",
     42                 skip, cut);
     43         return;
     44     }
     45     skip *= frameSize;
     46     cut *= frameSize;
     47 
     48     mFrontPadding = mSkip = skip;
     49     mBackPadding = cut;
     50     mCapacity = cut + 4096;
     51     mCutBuffer = new (std::nothrow) char[mCapacity];
     52     ALOGV("skipcutbuffer %zu %zu %d", skip, cut, mCapacity);
     53 }
     54 
     55 SkipCutBuffer::~SkipCutBuffer() {
     56     delete[] mCutBuffer;
     57 }
     58 
     59 void SkipCutBuffer::submit(MediaBuffer *buffer) {
     60     if (mCutBuffer == NULL) {
     61         // passthrough mode
     62         return;
     63     }
     64 
     65     int32_t offset = buffer->range_offset();
     66     int32_t buflen = buffer->range_length();
     67 
     68     // drop the initial data from the buffer if needed
     69     if (mFrontPadding > 0) {
     70         // still data left to drop
     71         int32_t to_drop = (buflen < mFrontPadding) ? buflen : mFrontPadding;
     72         offset += to_drop;
     73         buflen -= to_drop;
     74         buffer->set_range(offset, buflen);
     75         mFrontPadding -= to_drop;
     76     }
     77 
     78 
     79     // append data to cutbuffer
     80     char *src = ((char*) buffer->data()) + offset;
     81     write(src, buflen);
     82 
     83 
     84     // the mediabuffer is now empty. Fill it from cutbuffer, always leaving
     85     // at least mBackPadding bytes in the cutbuffer
     86     char *dst = (char*) buffer->data();
     87     size_t copied = read(dst, buffer->size());
     88     buffer->set_range(0, copied);
     89 }
     90 
     91 template <typename T>
     92 void SkipCutBuffer::submitInternal(const sp<T>& buffer) {
     93     if (mCutBuffer == NULL) {
     94         // passthrough mode
     95         return;
     96     }
     97 
     98     int32_t offset = buffer->offset();
     99     int32_t buflen = buffer->size();
    100 
    101     // drop the initial data from the buffer if needed
    102     if (mFrontPadding > 0) {
    103         // still data left to drop
    104         int32_t to_drop = (buflen < mFrontPadding) ? buflen : mFrontPadding;
    105         offset += to_drop;
    106         buflen -= to_drop;
    107         buffer->setRange(offset, buflen);
    108         mFrontPadding -= to_drop;
    109     }
    110 
    111 
    112     // append data to cutbuffer
    113     char *src = (char*) buffer->data();
    114     write(src, buflen);
    115 
    116 
    117     // the mediabuffer is now empty. Fill it from cutbuffer, always leaving
    118     // at least mBackPadding bytes in the cutbuffer
    119     char *dst = (char*) buffer->base();
    120     size_t copied = read(dst, buffer->capacity());
    121     buffer->setRange(0, copied);
    122 }
    123 
    124 void SkipCutBuffer::submit(const sp<ABuffer>& buffer) {
    125     submitInternal(buffer);
    126 }
    127 
    128 void SkipCutBuffer::submit(const sp<MediaCodecBuffer>& buffer) {
    129     submitInternal(buffer);
    130 }
    131 
    132 void SkipCutBuffer::clear() {
    133     mWriteHead = mReadHead = 0;
    134     mFrontPadding = mSkip;
    135 }
    136 
    137 void SkipCutBuffer::write(const char *src, size_t num) {
    138     int32_t sizeused = (mWriteHead - mReadHead);
    139     if (sizeused < 0) sizeused += mCapacity;
    140 
    141     // Everything must fit. Make sure the buffer is a little larger than needed,
    142     // so there is no ambiguity as to whether mWriteHead == mReadHead means buffer
    143     // full or empty
    144     size_t available = mCapacity - sizeused - 32;
    145     if (available < num) {
    146         int32_t newcapacity = mCapacity + (num - available);
    147         char * newbuffer = new char[newcapacity];
    148         memcpy(newbuffer, mCutBuffer, mCapacity);
    149         delete [] mCutBuffer;
    150         mCapacity = newcapacity;
    151         mCutBuffer = newbuffer;
    152         ALOGV("reallocated buffer at size %d", newcapacity);
    153     }
    154 
    155     size_t copyfirst = (mCapacity - mWriteHead);
    156     if (copyfirst > num) copyfirst = num;
    157     if (copyfirst) {
    158         memcpy(mCutBuffer + mWriteHead, src, copyfirst);
    159         num -= copyfirst;
    160         src += copyfirst;
    161         mWriteHead += copyfirst;
    162         CHECK_LE(mWriteHead, mCapacity);
    163         if (mWriteHead == mCapacity) mWriteHead = 0;
    164         if (num) {
    165             memcpy(mCutBuffer, src, num);
    166             mWriteHead += num;
    167         }
    168     }
    169 }
    170 
    171 size_t SkipCutBuffer::read(char *dst, size_t num) {
    172     int32_t available = (mWriteHead - mReadHead);
    173     if (available < 0) available += mCapacity;
    174 
    175     available -= mBackPadding;
    176     if (available <=0) {
    177         return 0;
    178     }
    179     if (available < int32_t(num)) {
    180         num = available;
    181     }
    182 
    183     size_t copyfirst = (mCapacity - mReadHead);
    184     if (copyfirst > num) copyfirst = num;
    185     if (copyfirst) {
    186         memcpy(dst, mCutBuffer + mReadHead, copyfirst);
    187         num -= copyfirst;
    188         dst += copyfirst;
    189         mReadHead += copyfirst;
    190         CHECK_LE(mReadHead, mCapacity);
    191         if (mReadHead == mCapacity) mReadHead = 0;
    192         if (num) {
    193             memcpy(dst, mCutBuffer, num);
    194             mReadHead += num;
    195         }
    196     }
    197     return available;
    198 }
    199 
    200 size_t SkipCutBuffer::size() {
    201     int32_t available = (mWriteHead - mReadHead);
    202     if (available < 0) available += mCapacity;
    203     return available;
    204 }
    205 
    206 }  // namespace android
    207