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 25namespace android { 26 27SkipCutBuffer::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 55SkipCutBuffer::~SkipCutBuffer() { 56 delete[] mCutBuffer; 57} 58 59void 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 91void SkipCutBuffer::submit(const sp<ABuffer>& buffer) { 92 if (mCutBuffer == NULL) { 93 // passthrough mode 94 return; 95 } 96 97 int32_t offset = buffer->offset(); 98 int32_t buflen = buffer->size(); 99 100 // drop the initial data from the buffer if needed 101 if (mFrontPadding > 0) { 102 // still data left to drop 103 int32_t to_drop = (buflen < mFrontPadding) ? buflen : mFrontPadding; 104 offset += to_drop; 105 buflen -= to_drop; 106 buffer->setRange(offset, buflen); 107 mFrontPadding -= to_drop; 108 } 109 110 111 // append data to cutbuffer 112 char *src = (char*) buffer->data(); 113 write(src, buflen); 114 115 116 // the mediabuffer is now empty. Fill it from cutbuffer, always leaving 117 // at least mBackPadding bytes in the cutbuffer 118 char *dst = (char*) buffer->base(); 119 size_t copied = read(dst, buffer->capacity()); 120 buffer->setRange(0, copied); 121} 122 123void SkipCutBuffer::clear() { 124 mWriteHead = mReadHead = 0; 125 mFrontPadding = mSkip; 126} 127 128void SkipCutBuffer::write(const char *src, size_t num) { 129 int32_t sizeused = (mWriteHead - mReadHead); 130 if (sizeused < 0) sizeused += mCapacity; 131 132 // Everything must fit. Make sure the buffer is a little larger than needed, 133 // so there is no ambiguity as to whether mWriteHead == mReadHead means buffer 134 // full or empty 135 size_t available = mCapacity - sizeused - 32; 136 if (available < num) { 137 int32_t newcapacity = mCapacity + (num - available); 138 char * newbuffer = new char[newcapacity]; 139 memcpy(newbuffer, mCutBuffer, mCapacity); 140 delete [] mCutBuffer; 141 mCapacity = newcapacity; 142 mCutBuffer = newbuffer; 143 ALOGV("reallocated buffer at size %d", newcapacity); 144 } 145 146 size_t copyfirst = (mCapacity - mWriteHead); 147 if (copyfirst > num) copyfirst = num; 148 if (copyfirst) { 149 memcpy(mCutBuffer + mWriteHead, src, copyfirst); 150 num -= copyfirst; 151 src += copyfirst; 152 mWriteHead += copyfirst; 153 CHECK_LE(mWriteHead, mCapacity); 154 if (mWriteHead == mCapacity) mWriteHead = 0; 155 if (num) { 156 memcpy(mCutBuffer, src, num); 157 mWriteHead += num; 158 } 159 } 160} 161 162size_t SkipCutBuffer::read(char *dst, size_t num) { 163 int32_t available = (mWriteHead - mReadHead); 164 if (available < 0) available += mCapacity; 165 166 available -= mBackPadding; 167 if (available <=0) { 168 return 0; 169 } 170 if (available < int32_t(num)) { 171 num = available; 172 } 173 174 size_t copyfirst = (mCapacity - mReadHead); 175 if (copyfirst > num) copyfirst = num; 176 if (copyfirst) { 177 memcpy(dst, mCutBuffer + mReadHead, copyfirst); 178 num -= copyfirst; 179 dst += copyfirst; 180 mReadHead += copyfirst; 181 CHECK_LE(mReadHead, mCapacity); 182 if (mReadHead == mCapacity) mReadHead = 0; 183 if (num) { 184 memcpy(dst, mCutBuffer, num); 185 mReadHead += num; 186 } 187 } 188 return available; 189} 190 191size_t SkipCutBuffer::size() { 192 int32_t available = (mWriteHead - mReadHead); 193 if (available < 0) available += mCapacity; 194 return available; 195} 196 197} // namespace android 198