blob: 4753dd4655bde76201fcd9fff678cc6616b19ffc [file] [log] [blame]
Chih-Chung Chang99698662011-06-30 14:21:38 +08001/*
2 * Copyright (C) 2011 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
Chih-Chung Chang3d974e72011-08-18 19:41:30 +080017//#define LOG_NDEBUG 0
18#define LOG_TAG "VideoEditorSRC"
Chih-Chung Chang99698662011-06-30 14:21:38 +080019
James Dong00f742c2012-01-13 17:34:42 -080020#include <stdlib.h>
21#include <utils/Log.h>
Glenn Kasten7bdbbc72011-12-16 11:07:44 -080022#include <audio_utils/primitives.h>
James Dongc4689fa2012-02-08 13:51:46 -080023#include <media/stagefright/foundation/ADebug.h>
Chih-Chung Chang99698662011-06-30 14:21:38 +080024#include <media/stagefright/MetaData.h>
Chih-Chung Chang99698662011-06-30 14:21:38 +080025#include <media/stagefright/MediaBuffer.h>
26#include <media/stagefright/MediaDefs.h>
James Dong00f742c2012-01-13 17:34:42 -080027#include "VideoEditorSRC.h"
28
Chih-Chung Chang99698662011-06-30 14:21:38 +080029
30namespace android {
31
Chih-Chung Chang3d974e72011-08-18 19:41:30 +080032VideoEditorSRC::VideoEditorSRC(const sp<MediaSource> &source) {
James Dong00f742c2012-01-13 17:34:42 -080033 ALOGV("VideoEditorSRC %p(%p)", this, source.get());
34 static const int32_t kDefaultSamplingFreqencyHz = kFreq32000Hz;
Chih-Chung Chang99698662011-06-30 14:21:38 +080035 mSource = source;
36 mResampler = NULL;
Chih-Chung Chang99698662011-06-30 14:21:38 +080037 mChannelCnt = 0;
38 mSampleRate = 0;
James Dong00f742c2012-01-13 17:34:42 -080039 mOutputSampleRate = kDefaultSamplingFreqencyHz;
Chih-Chung Chang99698662011-06-30 14:21:38 +080040 mStarted = false;
Chih-Chung Chang99698662011-06-30 14:21:38 +080041 mInitialTimeStampUs = -1;
42 mAccuOutBufferSize = 0;
43 mSeekTimeUs = -1;
Chih-Chung Chang3d974e72011-08-18 19:41:30 +080044 mBuffer = NULL;
Chih-Chung Chang99698662011-06-30 14:21:38 +080045 mLeftover = 0;
Chih-Chung Chang3d974e72011-08-18 19:41:30 +080046 mFormatChanged = false;
Chih-Chung Chang2db76712011-11-15 19:47:25 +080047 mStopPending = false;
Chih-Chung Chang3d974e72011-08-18 19:41:30 +080048 mSeekMode = ReadOptions::SEEK_PREVIOUS_SYNC;
Chih-Chung Chang99698662011-06-30 14:21:38 +080049
50 // Input Source validation
51 sp<MetaData> format = mSource->getFormat();
52 const char *mime;
Chih-Chung Chang3d974e72011-08-18 19:41:30 +080053 CHECK(format->findCString(kKeyMIMEType, &mime));
Chih-Chung Chang99698662011-06-30 14:21:38 +080054 CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW));
55
Chih-Chung Chang3d974e72011-08-18 19:41:30 +080056 // Set the metadata of the output after resampling.
57 mOutputFormat = new MetaData;
58 mOutputFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
James Dong00f742c2012-01-13 17:34:42 -080059 mOutputFormat->setInt32(kKeySampleRate, kDefaultSamplingFreqencyHz);
60 mOutputFormat->setInt32(kKeyChannelCount, 2); // always stereo
Chih-Chung Chang99698662011-06-30 14:21:38 +080061}
62
Chih-Chung Chang3d974e72011-08-18 19:41:30 +080063VideoEditorSRC::~VideoEditorSRC() {
James Dong00f742c2012-01-13 17:34:42 -080064 ALOGV("~VideoEditorSRC %p(%p)", this, mSource.get());
Chih-Chung Chang3d974e72011-08-18 19:41:30 +080065 stop();
Chih-Chung Chang99698662011-06-30 14:21:38 +080066}
67
Chih-Chung Chang3d974e72011-08-18 19:41:30 +080068status_t VideoEditorSRC::start(MetaData *params) {
James Dong00f742c2012-01-13 17:34:42 -080069 ALOGV("start %p(%p)", this, mSource.get());
Chih-Chung Chang99698662011-06-30 14:21:38 +080070 CHECK(!mStarted);
Chih-Chung Chang99698662011-06-30 14:21:38 +080071
Rajneesh Chowdury1c3c5432011-07-20 13:47:34 -070072 // Set resampler if required
Chih-Chung Chang3d974e72011-08-18 19:41:30 +080073 checkAndSetResampler();
Rajneesh Chowdury1c3c5432011-07-20 13:47:34 -070074
Chih-Chung Chang99698662011-06-30 14:21:38 +080075 mSeekTimeUs = -1;
Chih-Chung Chang3d974e72011-08-18 19:41:30 +080076 mSeekMode = ReadOptions::SEEK_PREVIOUS_SYNC;
Chih-Chung Chang99698662011-06-30 14:21:38 +080077 mStarted = true;
78 mSource->start();
79
80 return OK;
81}
82
83status_t VideoEditorSRC::stop() {
James Dong00f742c2012-01-13 17:34:42 -080084 ALOGV("stop %p(%p)", this, mSource.get());
85 if (!mStarted) {
86 return OK;
87 }
88
Chih-Chung Chang3d974e72011-08-18 19:41:30 +080089 if (mBuffer) {
90 mBuffer->release();
91 mBuffer = NULL;
92 }
Chih-Chung Chang99698662011-06-30 14:21:38 +080093 mSource->stop();
James Dong00f742c2012-01-13 17:34:42 -080094 if (mResampler != NULL) {
Chih-Chung Chang99698662011-06-30 14:21:38 +080095 delete mResampler;
96 mResampler = NULL;
97 }
James Dong00f742c2012-01-13 17:34:42 -080098
Chih-Chung Chang99698662011-06-30 14:21:38 +080099 mStarted = false;
100 mInitialTimeStampUs = -1;
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800101 mAccuOutBufferSize = 0;
Chih-Chung Chang99698662011-06-30 14:21:38 +0800102 mLeftover = 0;
Chih-Chung Chang99698662011-06-30 14:21:38 +0800103
104 return OK;
105}
106
107sp<MetaData> VideoEditorSRC::getFormat() {
James Dong00f742c2012-01-13 17:34:42 -0800108 ALOGV("getFormat");
Chih-Chung Chang99698662011-06-30 14:21:38 +0800109 return mOutputFormat;
110}
111
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800112status_t VideoEditorSRC::read(
Chih-Chung Chang99698662011-06-30 14:21:38 +0800113 MediaBuffer **buffer_out, const ReadOptions *options) {
James Dong00f742c2012-01-13 17:34:42 -0800114 ALOGV("read %p(%p)", this, mSource.get());
Chih-Chung Chang99698662011-06-30 14:21:38 +0800115 *buffer_out = NULL;
Chih-Chung Chang99698662011-06-30 14:21:38 +0800116
117 if (!mStarted) {
118 return ERROR_END_OF_STREAM;
119 }
120
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800121 if (mResampler) {
Chih-Chung Chang99698662011-06-30 14:21:38 +0800122 // Store the seek parameters
123 int64_t seekTimeUs;
124 ReadOptions::SeekMode mode = ReadOptions::SEEK_PREVIOUS_SYNC;
125 if (options && options->getSeekTo(&seekTimeUs, &mode)) {
Steve Block2703f232011-10-20 11:56:09 +0100126 ALOGV("read Seek %lld", seekTimeUs);
Chih-Chung Chang99698662011-06-30 14:21:38 +0800127 mSeekTimeUs = seekTimeUs;
128 mSeekMode = mode;
129 }
130
131 // We ask for 1024 frames in output
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800132 // resampler output is always 2 channels and 32 bits
James Dong00f742c2012-01-13 17:34:42 -0800133 const size_t kOutputFrameCount = 1024;
134 const size_t kBytes = kOutputFrameCount * 2 * sizeof(int32_t);
135 int32_t *pTmpBuffer = (int32_t *)calloc(1, kBytes);
136 if (!pTmpBuffer) {
137 ALOGE("calloc failed to allocate memory: %d bytes", kBytes);
138 return NO_MEMORY;
139 }
140
Chih-Chung Chang99698662011-06-30 14:21:38 +0800141 // Resample to target quality
James Dong00f742c2012-01-13 17:34:42 -0800142 mResampler->resample(pTmpBuffer, kOutputFrameCount, this);
Chih-Chung Chang99698662011-06-30 14:21:38 +0800143
Chih-Chung Chang2db76712011-11-15 19:47:25 +0800144 if (mStopPending) {
145 stop();
146 mStopPending = false;
147 }
148
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800149 // Change resampler and retry if format change happened
150 if (mFormatChanged) {
151 mFormatChanged = false;
152 checkAndSetResampler();
153 free(pTmpBuffer);
154 return read(buffer_out, NULL);
Chih-Chung Chang99698662011-06-30 14:21:38 +0800155 }
Chih-Chung Chang99698662011-06-30 14:21:38 +0800156
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800157 // Create a new MediaBuffer
James Dong00f742c2012-01-13 17:34:42 -0800158 int32_t outBufferSize = kOutputFrameCount * 2 * sizeof(int16_t);
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800159 MediaBuffer* outBuffer = new MediaBuffer(outBufferSize);
Chih-Chung Chang99698662011-06-30 14:21:38 +0800160
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800161 // Convert back to 2 channels and 16 bits
Glenn Kasten7bdbbc72011-12-16 11:07:44 -0800162 ditherAndClamp(
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800163 (int32_t *)((uint8_t*)outBuffer->data() + outBuffer->range_offset()),
James Dong00f742c2012-01-13 17:34:42 -0800164 pTmpBuffer, kOutputFrameCount);
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800165 free(pTmpBuffer);
Chih-Chung Chang99698662011-06-30 14:21:38 +0800166
167 // Compute and set the new timestamp
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800168 sp<MetaData> to = outBuffer->meta_data();
169 int64_t totalOutDurationUs = (mAccuOutBufferSize * 1000000) / (mOutputSampleRate * 2 * 2);
Chih-Chung Chang99698662011-06-30 14:21:38 +0800170 int64_t timeUs = mInitialTimeStampUs + totalOutDurationUs;
171 to->setInt64(kKeyTime, timeUs);
Chih-Chung Chang99698662011-06-30 14:21:38 +0800172
173 // update the accumulate size
174 mAccuOutBufferSize += outBufferSize;
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800175 *buffer_out = outBuffer;
Chih-Chung Chang99698662011-06-30 14:21:38 +0800176 } else {
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800177 // Resampling not required. Read and pass-through.
Chih-Chung Chang99698662011-06-30 14:21:38 +0800178 MediaBuffer *aBuffer;
179 status_t err = mSource->read(&aBuffer, options);
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800180 if (err != OK) {
Steve Block2703f232011-10-20 11:56:09 +0100181 ALOGV("read returns err = %d", err);
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800182 }
183
184 if (err == INFO_FORMAT_CHANGED) {
185 checkAndSetResampler();
186 return read(buffer_out, NULL);
187 }
188
189 // EOS or some other error
Chih-Chung Chang99698662011-06-30 14:21:38 +0800190 if(err != OK) {
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800191 stop();
Chih-Chung Chang99698662011-06-30 14:21:38 +0800192 *buffer_out = NULL;
Chih-Chung Chang99698662011-06-30 14:21:38 +0800193 return err;
194 }
195 *buffer_out = aBuffer;
196 }
197
198 return OK;
199}
200
John Grossman7719f632012-02-10 13:46:24 -0800201status_t VideoEditorSRC::getNextBuffer(AudioBufferProvider::Buffer *pBuffer, int64_t pts) {
James Dong00f742c2012-01-13 17:34:42 -0800202 ALOGV("getNextBuffer %d, chan = %d", pBuffer->frameCount, mChannelCnt);
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800203 uint32_t done = 0;
204 uint32_t want = pBuffer->frameCount * mChannelCnt * 2;
205 pBuffer->raw = malloc(want);
Chih-Chung Chang99698662011-06-30 14:21:38 +0800206
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800207 while (mStarted && want > 0) {
208 // If we don't have any data left, read a new buffer.
209 if (!mBuffer) {
210 // if we seek, reset the initial time stamp and accumulated time
211 ReadOptions options;
212 if (mSeekTimeUs >= 0) {
Steve Block2703f232011-10-20 11:56:09 +0100213 ALOGV("%p cacheMore_l Seek requested = %lld", this, mSeekTimeUs);
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800214 ReadOptions::SeekMode mode = mSeekMode;
215 options.setSeekTo(mSeekTimeUs, mode);
216 mSeekTimeUs = -1;
217 mInitialTimeStampUs = -1;
218 mAccuOutBufferSize = 0;
Rajneesh Chowdury1c3c5432011-07-20 13:47:34 -0700219 }
Chih-Chung Chang99698662011-06-30 14:21:38 +0800220
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800221 status_t err = mSource->read(&mBuffer, &options);
Chih-Chung Chang99698662011-06-30 14:21:38 +0800222
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800223 if (err != OK) {
224 free(pBuffer->raw);
225 pBuffer->raw = NULL;
226 pBuffer->frameCount = 0;
227 }
228
229 if (err == INFO_FORMAT_CHANGED) {
Steve Block2703f232011-10-20 11:56:09 +0100230 ALOGV("getNextBuffer: source read returned INFO_FORMAT_CHANGED");
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800231 // At this point we cannot switch to a new AudioResampler because
232 // we are in a callback called by the AudioResampler itself. So
233 // just remember the fact that the format has changed, and let
234 // read() handles this.
235 mFormatChanged = true;
236 return err;
237 }
238
239 // EOS or some other error
240 if (err != OK) {
Steve Block2703f232011-10-20 11:56:09 +0100241 ALOGV("EOS or some err: %d", err);
Chih-Chung Chang2db76712011-11-15 19:47:25 +0800242 // We cannot call stop() here because stop() will release the
243 // AudioResampler, and we are in a callback of the AudioResampler.
244 // So just remember the fact and let read() call stop().
245 mStopPending = true;
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800246 return err;
247 }
248
249 CHECK(mBuffer);
250 mLeftover = mBuffer->range_length();
Chih-Chung Chang99698662011-06-30 14:21:38 +0800251 if (mInitialTimeStampUs == -1) {
252 int64_t curTS;
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800253 sp<MetaData> from = mBuffer->meta_data();
Chih-Chung Chang99698662011-06-30 14:21:38 +0800254 from->findInt64(kKeyTime, &curTS);
Steve Block2703f232011-10-20 11:56:09 +0100255 ALOGV("setting mInitialTimeStampUs to %lld", mInitialTimeStampUs);
Chih-Chung Chang99698662011-06-30 14:21:38 +0800256 mInitialTimeStampUs = curTS;
257 }
Chih-Chung Chang99698662011-06-30 14:21:38 +0800258 }
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800259
260 // Now copy data to the destination
261 uint32_t todo = mLeftover;
262 if (todo > want) {
263 todo = want;
264 }
265
266 uint8_t* end = (uint8_t*)mBuffer->data() + mBuffer->range_offset()
267 + mBuffer->range_length();
268 memcpy((uint8_t*)pBuffer->raw + done, end - mLeftover, todo);
269 done += todo;
270 want -= todo;
271 mLeftover -= todo;
272
273 // Release MediaBuffer as soon as possible.
274 if (mLeftover == 0) {
275 mBuffer->release();
276 mBuffer = NULL;
277 }
Chih-Chung Chang99698662011-06-30 14:21:38 +0800278 }
279
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800280 pBuffer->frameCount = done / (mChannelCnt * 2);
Steve Block2703f232011-10-20 11:56:09 +0100281 ALOGV("getNextBuffer done %d", pBuffer->frameCount);
Chih-Chung Chang99698662011-06-30 14:21:38 +0800282 return OK;
283}
284
285
286void VideoEditorSRC::releaseBuffer(AudioBufferProvider::Buffer *pBuffer) {
James Dong00f742c2012-01-13 17:34:42 -0800287 ALOGV("releaseBuffer: %p", pBuffers);
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800288 free(pBuffer->raw);
289 pBuffer->raw = NULL;
Chih-Chung Chang99698662011-06-30 14:21:38 +0800290 pBuffer->frameCount = 0;
291}
292
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800293void VideoEditorSRC::checkAndSetResampler() {
Steve Block2703f232011-10-20 11:56:09 +0100294 ALOGV("checkAndSetResampler");
Rajneesh Chowdury1c3c5432011-07-20 13:47:34 -0700295
James Dong00f742c2012-01-13 17:34:42 -0800296 static const uint16_t kUnityGain = 0x1000;
Rajneesh Chowdury1c3c5432011-07-20 13:47:34 -0700297 sp<MetaData> format = mSource->getFormat();
298 const char *mime;
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800299 CHECK(format->findCString(kKeyMIMEType, &mime));
Rajneesh Chowdury1c3c5432011-07-20 13:47:34 -0700300 CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW));
301
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800302 CHECK(format->findInt32(kKeySampleRate, &mSampleRate));
303 CHECK(format->findInt32(kKeyChannelCount, &mChannelCnt));
Rajneesh Chowdury1c3c5432011-07-20 13:47:34 -0700304
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800305 // If a resampler exists, delete it first
Rajneesh Chowdury1c3c5432011-07-20 13:47:34 -0700306 if (mResampler != NULL) {
307 delete mResampler;
308 mResampler = NULL;
309 }
310
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800311 // Clear previous buffer
312 if (mBuffer) {
313 mBuffer->release();
314 mBuffer = NULL;
Rajneesh Chowdury1c3c5432011-07-20 13:47:34 -0700315 }
316
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800317 if (mSampleRate != mOutputSampleRate || mChannelCnt != 2) {
James Dong00f742c2012-01-13 17:34:42 -0800318 ALOGV("Resampling required (%d => %d Hz, # channels = %d)",
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800319 mSampleRate, mOutputSampleRate, mChannelCnt);
Rajneesh Chowdury1c3c5432011-07-20 13:47:34 -0700320
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800321 mResampler = AudioResampler::create(
322 16 /* bit depth */,
323 mChannelCnt,
324 mOutputSampleRate,
325 AudioResampler::DEFAULT);
326 CHECK(mResampler);
327 mResampler->setSampleRate(mSampleRate);
James Dong00f742c2012-01-13 17:34:42 -0800328 mResampler->setVolume(kUnityGain, kUnityGain);
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800329 } else {
James Dong00f742c2012-01-13 17:34:42 -0800330 ALOGV("Resampling not required (%d => %d Hz, # channels = %d)",
331 mSampleRate, mOutputSampleRate, mChannelCnt);
Chih-Chung Chang3d974e72011-08-18 19:41:30 +0800332 }
Rajneesh Chowdury1c3c5432011-07-20 13:47:34 -0700333}
334
Chih-Chung Chang99698662011-06-30 14:21:38 +0800335} //namespce android