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