1/*
2 * Copyright (C) 2014 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 "MediaFilter"
19
20#include <inttypes.h>
21#include <utils/Trace.h>
22
23#include <binder/MemoryDealer.h>
24
25#include <media/stagefright/BufferProducerWrapper.h>
26#include <media/stagefright/foundation/ABuffer.h>
27#include <media/stagefright/foundation/ADebug.h>
28#include <media/stagefright/foundation/AMessage.h>
29
30#include <media/stagefright/MediaDefs.h>
31#include <media/stagefright/MediaErrors.h>
32#include <media/stagefright/MediaFilter.h>
33
34#include <gui/BufferItem.h>
35
36#include "ColorConvert.h"
37#include "GraphicBufferListener.h"
38#include "IntrinsicBlurFilter.h"
39#include "RSFilter.h"
40#include "SaturationFilter.h"
41#include "ZeroFilter.h"
42
43namespace android {
44
45// parameter: number of input and output buffers
46static const size_t kBufferCountActual = 4;
47
48MediaFilter::MediaFilter()
49    : mState(UNINITIALIZED),
50      mGeneration(0),
51      mGraphicBufferListener(NULL) {
52}
53
54MediaFilter::~MediaFilter() {
55}
56
57//////////////////// PUBLIC FUNCTIONS //////////////////////////////////////////
58
59void MediaFilter::setNotificationMessage(const sp<AMessage> &msg) {
60    mNotify = msg;
61}
62
63void MediaFilter::initiateAllocateComponent(const sp<AMessage> &msg) {
64    msg->setWhat(kWhatAllocateComponent);
65    msg->setTarget(this);
66    msg->post();
67}
68
69void MediaFilter::initiateConfigureComponent(const sp<AMessage> &msg) {
70    msg->setWhat(kWhatConfigureComponent);
71    msg->setTarget(this);
72    msg->post();
73}
74
75void MediaFilter::initiateCreateInputSurface() {
76    (new AMessage(kWhatCreateInputSurface, this))->post();
77}
78
79void MediaFilter::initiateSetInputSurface(
80        const sp<PersistentSurface> & /* surface */) {
81    ALOGW("initiateSetInputSurface() unsupported");
82}
83
84void MediaFilter::initiateStart() {
85    (new AMessage(kWhatStart, this))->post();
86}
87
88void MediaFilter::initiateShutdown(bool keepComponentAllocated) {
89    sp<AMessage> msg = new AMessage(kWhatShutdown, this);
90    msg->setInt32("keepComponentAllocated", keepComponentAllocated);
91    msg->post();
92}
93
94void MediaFilter::signalFlush() {
95    (new AMessage(kWhatFlush, this))->post();
96}
97
98void MediaFilter::signalResume() {
99    (new AMessage(kWhatResume, this))->post();
100}
101
102// nothing to do
103void MediaFilter::signalRequestIDRFrame() {
104    return;
105}
106
107void MediaFilter::signalSetParameters(const sp<AMessage> &params) {
108    sp<AMessage> msg = new AMessage(kWhatSetParameters, this);
109    msg->setMessage("params", params);
110    msg->post();
111}
112
113void MediaFilter::signalEndOfInputStream() {
114    (new AMessage(kWhatSignalEndOfInputStream, this))->post();
115}
116
117void MediaFilter::onMessageReceived(const sp<AMessage> &msg) {
118    switch (msg->what()) {
119        case kWhatAllocateComponent:
120        {
121            onAllocateComponent(msg);
122            break;
123        }
124        case kWhatConfigureComponent:
125        {
126            onConfigureComponent(msg);
127            break;
128        }
129        case kWhatStart:
130        {
131            onStart();
132            break;
133        }
134        case kWhatProcessBuffers:
135        {
136            processBuffers();
137            break;
138        }
139        case kWhatInputBufferFilled:
140        {
141            onInputBufferFilled(msg);
142            break;
143        }
144        case kWhatOutputBufferDrained:
145        {
146            onOutputBufferDrained(msg);
147            break;
148        }
149        case kWhatShutdown:
150        {
151            onShutdown(msg);
152            break;
153        }
154        case kWhatFlush:
155        {
156            onFlush();
157            break;
158        }
159        case kWhatResume:
160        {
161            // nothing to do
162            break;
163        }
164        case kWhatSetParameters:
165        {
166            onSetParameters(msg);
167            break;
168        }
169        case kWhatCreateInputSurface:
170        {
171            onCreateInputSurface();
172            break;
173        }
174        case GraphicBufferListener::kWhatFrameAvailable:
175        {
176            onInputFrameAvailable();
177            break;
178        }
179        case kWhatSignalEndOfInputStream:
180        {
181            onSignalEndOfInputStream();
182            break;
183        }
184        default:
185        {
186            ALOGE("Message not handled:\n%s", msg->debugString().c_str());
187            break;
188        }
189    }
190}
191
192//////////////////// PORT DESCRIPTION //////////////////////////////////////////
193
194MediaFilter::PortDescription::PortDescription() {
195}
196
197void MediaFilter::PortDescription::addBuffer(
198        IOMX::buffer_id id, const sp<ABuffer> &buffer) {
199    mBufferIDs.push_back(id);
200    mBuffers.push_back(buffer);
201}
202
203size_t MediaFilter::PortDescription::countBuffers() {
204    return mBufferIDs.size();
205}
206
207IOMX::buffer_id MediaFilter::PortDescription::bufferIDAt(size_t index) const {
208    return mBufferIDs.itemAt(index);
209}
210
211sp<ABuffer> MediaFilter::PortDescription::bufferAt(size_t index) const {
212    return mBuffers.itemAt(index);
213}
214
215//////////////////// HELPER FUNCTIONS //////////////////////////////////////////
216
217void MediaFilter::signalProcessBuffers() {
218    (new AMessage(kWhatProcessBuffers, this))->post();
219}
220
221void MediaFilter::signalError(status_t error) {
222    sp<AMessage> notify = mNotify->dup();
223    notify->setInt32("what", CodecBase::kWhatError);
224    notify->setInt32("err", error);
225    notify->post();
226}
227
228status_t MediaFilter::allocateBuffersOnPort(OMX_U32 portIndex) {
229    CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
230    const bool isInput = portIndex == kPortIndexInput;
231    const size_t bufferSize = isInput ? mMaxInputSize : mMaxOutputSize;
232
233    CHECK(mDealer[portIndex] == NULL);
234    CHECK(mBuffers[portIndex].isEmpty());
235
236    ALOGV("Allocating %zu buffers of size %zu on %s port",
237            kBufferCountActual, bufferSize,
238            isInput ? "input" : "output");
239
240    size_t totalSize = kBufferCountActual * bufferSize;
241
242    mDealer[portIndex] = new MemoryDealer(totalSize, "MediaFilter");
243
244    for (size_t i = 0; i < kBufferCountActual; ++i) {
245        sp<IMemory> mem = mDealer[portIndex]->allocate(bufferSize);
246        CHECK(mem.get() != NULL);
247
248        BufferInfo info;
249        info.mStatus = BufferInfo::OWNED_BY_US;
250        info.mBufferID = i;
251        info.mGeneration = mGeneration;
252        info.mOutputFlags = 0;
253        info.mData = new ABuffer(mem->pointer(), bufferSize);
254        info.mData->meta()->setInt64("timeUs", 0);
255
256        mBuffers[portIndex].push_back(info);
257
258        if (!isInput) {
259            mAvailableOutputBuffers.push(
260                    &mBuffers[portIndex].editItemAt(i));
261        }
262    }
263
264    sp<AMessage> notify = mNotify->dup();
265    notify->setInt32("what", CodecBase::kWhatBuffersAllocated);
266
267    notify->setInt32("portIndex", portIndex);
268
269    sp<PortDescription> desc = new PortDescription;
270
271    for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
272        const BufferInfo &info = mBuffers[portIndex][i];
273
274        desc->addBuffer(info.mBufferID, info.mData);
275    }
276
277    notify->setObject("portDesc", desc);
278    notify->post();
279
280    return OK;
281}
282
283MediaFilter::BufferInfo* MediaFilter::findBufferByID(
284        uint32_t portIndex, IOMX::buffer_id bufferID,
285        ssize_t *index) {
286    for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
287        BufferInfo *info = &mBuffers[portIndex].editItemAt(i);
288
289        if (info->mBufferID == bufferID) {
290            if (index != NULL) {
291                *index = i;
292            }
293            return info;
294        }
295    }
296
297    TRESPASS();
298
299    return NULL;
300}
301
302void MediaFilter::postFillThisBuffer(BufferInfo *info) {
303    ALOGV("postFillThisBuffer on buffer %d", info->mBufferID);
304    if (mPortEOS[kPortIndexInput]) {
305        return;
306    }
307
308    CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US);
309
310    info->mGeneration = mGeneration;
311
312    sp<AMessage> notify = mNotify->dup();
313    notify->setInt32("what", CodecBase::kWhatFillThisBuffer);
314    notify->setInt32("buffer-id", info->mBufferID);
315
316    info->mData->meta()->clear();
317    notify->setBuffer("buffer", info->mData);
318
319    sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, this);
320    reply->setInt32("buffer-id", info->mBufferID);
321
322    notify->setMessage("reply", reply);
323
324    info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
325    notify->post();
326}
327
328void MediaFilter::postDrainThisBuffer(BufferInfo *info) {
329    CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US);
330
331    info->mGeneration = mGeneration;
332
333    sp<AMessage> notify = mNotify->dup();
334    notify->setInt32("what", CodecBase::kWhatDrainThisBuffer);
335    notify->setInt32("buffer-id", info->mBufferID);
336    notify->setInt32("flags", info->mOutputFlags);
337    notify->setBuffer("buffer", info->mData);
338
339    sp<AMessage> reply = new AMessage(kWhatOutputBufferDrained, this);
340    reply->setInt32("buffer-id", info->mBufferID);
341
342    notify->setMessage("reply", reply);
343
344    notify->post();
345
346    info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
347}
348
349void MediaFilter::postEOS() {
350    sp<AMessage> notify = mNotify->dup();
351    notify->setInt32("what", CodecBase::kWhatEOS);
352    notify->setInt32("err", ERROR_END_OF_STREAM);
353    notify->post();
354
355    ALOGV("Sent kWhatEOS.");
356}
357
358void MediaFilter::sendFormatChange() {
359    sp<AMessage> notify = mNotify->dup();
360
361    notify->setInt32("what", kWhatOutputFormatChanged);
362
363    AString mime;
364    CHECK(mOutputFormat->findString("mime", &mime));
365    notify->setString("mime", mime.c_str());
366
367    notify->setInt32("stride", mStride);
368    notify->setInt32("slice-height", mSliceHeight);
369    notify->setInt32("color-format", mColorFormatOut);
370    notify->setRect("crop", 0, 0, mStride - 1, mSliceHeight - 1);
371    notify->setInt32("width", mWidth);
372    notify->setInt32("height", mHeight);
373
374    notify->post();
375}
376
377void MediaFilter::requestFillEmptyInput() {
378    if (mPortEOS[kPortIndexInput]) {
379        return;
380    }
381
382    for (size_t i = 0; i < mBuffers[kPortIndexInput].size(); ++i) {
383        BufferInfo *info = &mBuffers[kPortIndexInput].editItemAt(i);
384
385        if (info->mStatus == BufferInfo::OWNED_BY_US) {
386            postFillThisBuffer(info);
387        }
388    }
389}
390
391void MediaFilter::processBuffers() {
392    if (mAvailableInputBuffers.empty() || mAvailableOutputBuffers.empty()) {
393        ALOGV("Skipping process (buffers unavailable)");
394        return;
395    }
396
397    if (mPortEOS[kPortIndexOutput]) {
398        // TODO notify caller of queueInput error when it is supported
399        // in MediaCodec
400        ALOGW("Tried to process a buffer after EOS.");
401        return;
402    }
403
404    BufferInfo *inputInfo = mAvailableInputBuffers[0];
405    mAvailableInputBuffers.removeAt(0);
406    BufferInfo *outputInfo = mAvailableOutputBuffers[0];
407    mAvailableOutputBuffers.removeAt(0);
408
409    status_t err;
410    err = mFilter->processBuffers(inputInfo->mData, outputInfo->mData);
411    if (err != (status_t)OK) {
412        outputInfo->mData->meta()->setInt32("err", err);
413    }
414
415    int64_t timeUs;
416    CHECK(inputInfo->mData->meta()->findInt64("timeUs", &timeUs));
417    outputInfo->mData->meta()->setInt64("timeUs", timeUs);
418    outputInfo->mOutputFlags = 0;
419    int32_t eos = 0;
420    if (inputInfo->mData->meta()->findInt32("eos", &eos) && eos != 0) {
421        outputInfo->mOutputFlags |= OMX_BUFFERFLAG_EOS;
422        mPortEOS[kPortIndexOutput] = true;
423        outputInfo->mData->meta()->setInt32("eos", eos);
424        postEOS();
425        ALOGV("Output stream saw EOS.");
426    }
427
428    ALOGV("Processed input buffer %u [%zu], output buffer %u [%zu]",
429                inputInfo->mBufferID, inputInfo->mData->size(),
430                outputInfo->mBufferID, outputInfo->mData->size());
431
432    if (mGraphicBufferListener != NULL) {
433        delete inputInfo;
434    } else {
435        postFillThisBuffer(inputInfo);
436    }
437    postDrainThisBuffer(outputInfo);
438
439    // prevent any corner case where buffers could get stuck in queue
440    signalProcessBuffers();
441}
442
443void MediaFilter::onAllocateComponent(const sp<AMessage> &msg) {
444    CHECK_EQ(mState, UNINITIALIZED);
445
446    CHECK(msg->findString("componentName", &mComponentName));
447    const char* name = mComponentName.c_str();
448    if (!strcasecmp(name, "android.filter.zerofilter")) {
449        mFilter = new ZeroFilter;
450    } else if (!strcasecmp(name, "android.filter.saturation")) {
451        mFilter = new SaturationFilter;
452    } else if (!strcasecmp(name, "android.filter.intrinsicblur")) {
453        mFilter = new IntrinsicBlurFilter;
454    } else if (!strcasecmp(name, "android.filter.RenderScript")) {
455        mFilter = new RSFilter;
456    } else {
457        ALOGE("Unrecognized filter name: %s", name);
458        signalError(NAME_NOT_FOUND);
459        return;
460    }
461
462    sp<AMessage> notify = mNotify->dup();
463    notify->setInt32("what", kWhatComponentAllocated);
464    // HACK - need "OMX.google" to use MediaCodec's software renderer
465    notify->setString("componentName", "OMX.google.MediaFilter");
466    notify->post();
467    mState = INITIALIZED;
468    ALOGV("Handled kWhatAllocateComponent.");
469}
470
471void MediaFilter::onConfigureComponent(const sp<AMessage> &msg) {
472    // TODO: generalize to allow audio filters as well as video
473
474    CHECK_EQ(mState, INITIALIZED);
475
476    // get params - at least mime, width & height
477    AString mime;
478    CHECK(msg->findString("mime", &mime));
479    if (strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_RAW)) {
480        ALOGE("Bad mime: %s", mime.c_str());
481        signalError(BAD_VALUE);
482        return;
483    }
484
485    CHECK(msg->findInt32("width", &mWidth));
486    CHECK(msg->findInt32("height", &mHeight));
487    if (!msg->findInt32("stride", &mStride)) {
488        mStride = mWidth;
489    }
490    if (!msg->findInt32("slice-height", &mSliceHeight)) {
491        mSliceHeight = mHeight;
492    }
493
494    mMaxInputSize = mWidth * mHeight * 4;   // room for ARGB8888
495    int32_t maxInputSize;
496    if (msg->findInt32("max-input-size", &maxInputSize)
497            && (size_t)maxInputSize > mMaxInputSize) {
498        mMaxInputSize = maxInputSize;
499    }
500
501    if (!msg->findInt32("color-format", &mColorFormatIn)) {
502        // default to OMX_COLOR_Format32bitARGB8888
503        mColorFormatIn = OMX_COLOR_Format32bitARGB8888;
504        msg->setInt32("color-format", mColorFormatIn);
505    }
506    mColorFormatOut = mColorFormatIn;
507
508    mMaxOutputSize = mWidth * mHeight * 4;  // room for ARGB8888
509
510    AString cacheDir;
511    if (!msg->findString("cacheDir", &cacheDir)) {
512        ALOGE("Failed to find cache directory in config message.");
513        signalError(NAME_NOT_FOUND);
514        return;
515    }
516
517    status_t err;
518    err = mFilter->configure(msg);
519    if (err != (status_t)OK) {
520        ALOGE("Failed to configure filter component, err %d", err);
521        signalError(err);
522        return;
523    }
524
525    mInputFormat = new AMessage();
526    mInputFormat->setString("mime", mime.c_str());
527    mInputFormat->setInt32("stride", mStride);
528    mInputFormat->setInt32("slice-height", mSliceHeight);
529    mInputFormat->setInt32("color-format", mColorFormatIn);
530    mInputFormat->setRect("crop", 0, 0, mStride, mSliceHeight);
531    mInputFormat->setInt32("width", mWidth);
532    mInputFormat->setInt32("height", mHeight);
533
534    mOutputFormat = new AMessage();
535    mOutputFormat->setString("mime", mime.c_str());
536    mOutputFormat->setInt32("stride", mStride);
537    mOutputFormat->setInt32("slice-height", mSliceHeight);
538    mOutputFormat->setInt32("color-format", mColorFormatOut);
539    mOutputFormat->setRect("crop", 0, 0, mStride, mSliceHeight);
540    mOutputFormat->setInt32("width", mWidth);
541    mOutputFormat->setInt32("height", mHeight);
542
543    sp<AMessage> notify = mNotify->dup();
544    notify->setInt32("what", kWhatComponentConfigured);
545    notify->setString("componentName", "MediaFilter");
546    notify->setMessage("input-format", mInputFormat);
547    notify->setMessage("output-format", mOutputFormat);
548    notify->post();
549    mState = CONFIGURED;
550    ALOGV("Handled kWhatConfigureComponent.");
551
552    sendFormatChange();
553}
554
555void MediaFilter::onStart() {
556    CHECK_EQ(mState, CONFIGURED);
557
558    allocateBuffersOnPort(kPortIndexInput);
559
560    allocateBuffersOnPort(kPortIndexOutput);
561
562    status_t err = mFilter->start();
563    if (err != (status_t)OK) {
564        ALOGE("Failed to start filter component, err %d", err);
565        signalError(err);
566        return;
567    }
568
569    mPortEOS[kPortIndexInput] = false;
570    mPortEOS[kPortIndexOutput] = false;
571    mInputEOSResult = OK;
572    mState = STARTED;
573
574    requestFillEmptyInput();
575    ALOGV("Handled kWhatStart.");
576}
577
578void MediaFilter::onInputBufferFilled(const sp<AMessage> &msg) {
579    IOMX::buffer_id bufferID;
580    CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
581    BufferInfo *info = findBufferByID(kPortIndexInput, bufferID);
582
583    if (mState != STARTED) {
584        // we're not running, so we'll just keep that buffer...
585        info->mStatus = BufferInfo::OWNED_BY_US;
586        return;
587    }
588
589    if (info->mGeneration != mGeneration) {
590        ALOGV("Caught a stale input buffer [ID %d]", bufferID);
591        // buffer is stale (taken before a flush/shutdown) - repost it
592        CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_US);
593        postFillThisBuffer(info);
594        return;
595    }
596
597    CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_UPSTREAM);
598    info->mStatus = BufferInfo::OWNED_BY_US;
599
600    sp<ABuffer> buffer;
601    int32_t err = OK;
602    bool eos = false;
603
604    if (!msg->findBuffer("buffer", &buffer)) {
605        // these are unfilled buffers returned by client
606        CHECK(msg->findInt32("err", &err));
607
608        if (err == OK) {
609            // buffers with no errors are returned on MediaCodec.flush
610            ALOGV("saw unfilled buffer (MediaCodec.flush)");
611            postFillThisBuffer(info);
612            return;
613        } else {
614            ALOGV("saw error %d instead of an input buffer", err);
615            eos = true;
616        }
617
618        buffer.clear();
619    }
620
621    int32_t isCSD;
622    if (buffer != NULL && buffer->meta()->findInt32("csd", &isCSD)
623            && isCSD != 0) {
624        // ignore codec-specific data buffers
625        ALOGW("MediaFilter received a codec-specific data buffer");
626        postFillThisBuffer(info);
627        return;
628    }
629
630    int32_t tmp;
631    if (buffer != NULL && buffer->meta()->findInt32("eos", &tmp) && tmp) {
632        eos = true;
633        err = ERROR_END_OF_STREAM;
634    }
635
636    mAvailableInputBuffers.push_back(info);
637    processBuffers();
638
639    if (eos) {
640        mPortEOS[kPortIndexInput] = true;
641        mInputEOSResult = err;
642    }
643
644    ALOGV("Handled kWhatInputBufferFilled. [ID %u]", bufferID);
645}
646
647void MediaFilter::onOutputBufferDrained(const sp<AMessage> &msg) {
648    IOMX::buffer_id bufferID;
649    CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
650    BufferInfo *info = findBufferByID(kPortIndexOutput, bufferID);
651
652    if (mState != STARTED) {
653        // we're not running, so we'll just keep that buffer...
654        info->mStatus = BufferInfo::OWNED_BY_US;
655        return;
656    }
657
658    if (info->mGeneration != mGeneration) {
659        ALOGV("Caught a stale output buffer [ID %d]", bufferID);
660        // buffer is stale (taken before a flush/shutdown) - keep it
661        CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_US);
662        return;
663    }
664
665    CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_UPSTREAM);
666    info->mStatus = BufferInfo::OWNED_BY_US;
667
668    mAvailableOutputBuffers.push_back(info);
669
670    processBuffers();
671
672    ALOGV("Handled kWhatOutputBufferDrained. [ID %u]",
673            bufferID);
674}
675
676void MediaFilter::onShutdown(const sp<AMessage> &msg) {
677    mGeneration++;
678
679    if (mState != UNINITIALIZED) {
680        mFilter->reset();
681    }
682
683    int32_t keepComponentAllocated;
684    CHECK(msg->findInt32("keepComponentAllocated", &keepComponentAllocated));
685    if (!keepComponentAllocated || mState == UNINITIALIZED) {
686        mState = UNINITIALIZED;
687    } else {
688        mState = INITIALIZED;
689    }
690
691    sp<AMessage> notify = mNotify->dup();
692    notify->setInt32("what", CodecBase::kWhatShutdownCompleted);
693    notify->post();
694}
695
696void MediaFilter::onFlush() {
697    mGeneration++;
698
699    mAvailableInputBuffers.clear();
700    for (size_t i = 0; i < mBuffers[kPortIndexInput].size(); ++i) {
701        BufferInfo *info = &mBuffers[kPortIndexInput].editItemAt(i);
702        info->mStatus = BufferInfo::OWNED_BY_US;
703    }
704    mAvailableOutputBuffers.clear();
705    for (size_t i = 0; i < mBuffers[kPortIndexOutput].size(); ++i) {
706        BufferInfo *info = &mBuffers[kPortIndexOutput].editItemAt(i);
707        info->mStatus = BufferInfo::OWNED_BY_US;
708        mAvailableOutputBuffers.push_back(info);
709    }
710
711    mPortEOS[kPortIndexInput] = false;
712    mPortEOS[kPortIndexOutput] = false;
713    mInputEOSResult = OK;
714
715    sp<AMessage> notify = mNotify->dup();
716    notify->setInt32("what", CodecBase::kWhatFlushCompleted);
717    notify->post();
718    ALOGV("Posted kWhatFlushCompleted");
719
720    // MediaCodec returns all input buffers after flush, so in
721    // onInputBufferFilled we call postFillThisBuffer on them
722}
723
724void MediaFilter::onSetParameters(const sp<AMessage> &msg) {
725    CHECK(mState != STARTED);
726
727    status_t err = mFilter->setParameters(msg);
728    if (err != (status_t)OK) {
729        ALOGE("setParameters returned err %d", err);
730    }
731}
732
733void MediaFilter::onCreateInputSurface() {
734    CHECK(mState == CONFIGURED);
735
736    mGraphicBufferListener = new GraphicBufferListener;
737
738    sp<AMessage> notify = new AMessage();
739    notify->setTarget(this);
740    status_t err = mGraphicBufferListener->init(
741            notify, mStride, mSliceHeight, kBufferCountActual);
742
743    if (err != OK) {
744        ALOGE("Failed to init mGraphicBufferListener: %d", err);
745        signalError(err);
746        return;
747    }
748
749    sp<AMessage> reply = mNotify->dup();
750    reply->setInt32("what", CodecBase::kWhatInputSurfaceCreated);
751    reply->setObject(
752            "input-surface",
753            new BufferProducerWrapper(
754                    mGraphicBufferListener->getIGraphicBufferProducer()));
755    reply->post();
756}
757
758void MediaFilter::onInputFrameAvailable() {
759    BufferItem item = mGraphicBufferListener->getBufferItem();
760    sp<GraphicBuffer> buf = mGraphicBufferListener->getBuffer(item);
761
762    // get pointer to graphic buffer
763    void* bufPtr;
764    buf->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &bufPtr);
765
766    // HACK - there is no OMX_COLOR_FORMATTYPE value for RGBA, so the format
767    // conversion is hardcoded until we add this.
768    // TODO: check input format and convert only if necessary
769    // copy RGBA graphic buffer into temporary ARGB input buffer
770    BufferInfo *inputInfo = new BufferInfo;
771    inputInfo->mData = new ABuffer(buf->getWidth() * buf->getHeight() * 4);
772    ALOGV("Copying surface data into temp buffer.");
773    convertRGBAToARGB(
774            (uint8_t*)bufPtr, buf->getWidth(), buf->getHeight(),
775            buf->getStride(), inputInfo->mData->data());
776    inputInfo->mBufferID = item.mBuf;
777    inputInfo->mGeneration = mGeneration;
778    inputInfo->mOutputFlags = 0;
779    inputInfo->mStatus = BufferInfo::OWNED_BY_US;
780    inputInfo->mData->meta()->setInt64("timeUs", item.mTimestamp / 1000);
781
782    mAvailableInputBuffers.push_back(inputInfo);
783
784    mGraphicBufferListener->releaseBuffer(item);
785
786    signalProcessBuffers();
787}
788
789void MediaFilter::onSignalEndOfInputStream() {
790    // if using input surface, need to send an EOS output buffer
791    if (mGraphicBufferListener != NULL) {
792        Vector<BufferInfo> *outputBufs = &mBuffers[kPortIndexOutput];
793        BufferInfo* eosBuf;
794        bool foundBuf = false;
795        for (size_t i = 0; i < kBufferCountActual; i++) {
796            eosBuf = &outputBufs->editItemAt(i);
797            if (eosBuf->mStatus == BufferInfo::OWNED_BY_US) {
798                foundBuf = true;
799                break;
800            }
801        }
802
803        if (!foundBuf) {
804            ALOGE("onSignalEndOfInputStream failed to find an output buffer");
805            return;
806        }
807
808        eosBuf->mOutputFlags = OMX_BUFFERFLAG_EOS;
809        eosBuf->mGeneration = mGeneration;
810        eosBuf->mData->setRange(0, 0);
811        postDrainThisBuffer(eosBuf);
812        ALOGV("Posted EOS on output buffer %u", eosBuf->mBufferID);
813    }
814
815    mPortEOS[kPortIndexOutput] = true;
816    sp<AMessage> notify = mNotify->dup();
817    notify->setInt32("what", CodecBase::kWhatSignaledInputEOS);
818    notify->post();
819
820    ALOGV("Output stream saw EOS.");
821}
822
823}   // namespace android
824