Merge "NuPlayerDriver: fix misc. getCurrentPosition issue."
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 6c14a94..91341b8 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -185,6 +185,9 @@
 
     // MPEG user data offsets
     kKeyMpegUserData      = 'mpud', // size_t[]
+
+    // Size of NALU length in mkv/mp4
+    kKeyNalLengthSize     = 'nals', // int32_t
 };
 
 enum {
diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h
index 1ba9545..b8bb824 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/include/media/stagefright/NuMediaExtractor.h
@@ -114,6 +114,7 @@
 
     bool getTotalBitrate(int64_t *bitRate) const;
     void updateDurationAndBitrate();
+    status_t appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer);
 
     DISALLOW_EVIL_CONSTRUCTORS(NuMediaExtractor);
 };
diff --git a/include/ndk/NdkMediaCodec.h b/include/ndk/NdkMediaCodec.h
index 034cb35..c6035bd 100644
--- a/include/ndk/NdkMediaCodec.h
+++ b/include/ndk/NdkMediaCodec.h
@@ -154,6 +154,18 @@
 media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec*, size_t idx, bool render);
 
 /**
+ * Dynamically sets the output surface of a codec.
+ *
+ *  This can only be used if the codec was configured with an output surface.  The
+ *  new output surface should have a compatible usage type to the original output surface.
+ *  E.g. codecs may not support switching from a SurfaceTexture (GPU readable) output
+ *  to ImageReader (software readable) output.
+ *
+ * For more details, see the Java documentation for MediaCodec.setOutputSurface.
+ */
+media_status_t AMediaCodec_setOutputSurface(AMediaCodec*, ANativeWindow* surface);
+
+/**
  * If you are done with a buffer, use this call to update its surface timestamp
  * and return it to the codec to render it on the output surface. If you
  * have not specified an output surface when configuring this video codec,
@@ -164,7 +176,6 @@
 media_status_t AMediaCodec_releaseOutputBufferAtTime(
         AMediaCodec *mData, size_t idx, int64_t timestampNs);
 
-
 typedef enum {
     AMEDIACODECRYPTOINFO_MODE_CLEAR = 0,
     AMEDIACODECRYPTOINFO_MODE_AES_CTR = 1
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 5c13633..cede584 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -2142,11 +2142,7 @@
                 mPausedForBuffering = true;
                 onPause();
             }
-            // fall-thru
-        }
 
-        case Source::kWhatBufferingStart:
-        {
             notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_START, 0);
             break;
         }
@@ -2164,11 +2160,7 @@
                     onResume();
                 }
             }
-            // fall-thru
-        }
 
-        case Source::kWhatBufferingEnd:
-        {
             notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_END, 0);
             break;
         }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index ce87f87..4678956 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -525,7 +525,10 @@
         ALOGI("[%s] resubmitting CSD", mComponentName.c_str());
         msg->setBuffer("buffer", buffer);
         mCSDsToSubmit.removeAt(0);
-        CHECK(onInputBufferFetched(msg));
+        if (!onInputBufferFetched(msg)) {
+            handleError(UNKNOWN_ERROR);
+            return false;
+        }
         return true;
     }
 
@@ -862,7 +865,11 @@
 
         // copy into codec buffer
         if (buffer != codecBuffer) {
-            CHECK_LE(buffer->size(), codecBuffer->capacity());
+            if (buffer->size() > codecBuffer->capacity()) {
+                handleError(ERROR_BUFFER_TOO_SMALL);
+                mDequeuedInputBuffers.push_back(bufferIx);
+                return false;
+            }
             codecBuffer->setRange(0, buffer->size());
             memcpy(codecBuffer->data(), buffer->data(), buffer->size());
         }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index fba4540..0176eafa 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -46,8 +46,6 @@
         kWhatFlagsChanged,
         kWhatVideoSizeChanged,
         kWhatBufferingUpdate,
-        kWhatBufferingStart,
-        kWhatBufferingEnd,
         kWhatPauseOnBufferingStart,
         kWhatResumeOnBufferingEnd,
         kWhatCacheStats,
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index c861fd1..2ecab6d 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -725,7 +725,7 @@
         mBuffering = true;
 
         sp<AMessage> notify = dupNotify();
-        notify->setInt32("what", kWhatBufferingStart);
+        notify->setInt32("what", kWhatPauseOnBufferingStart);
         notify->post();
     }
 }
@@ -741,7 +741,7 @@
         mBuffering = false;
 
         sp<AMessage> notify = dupNotify();
-        notify->setInt32("what", kWhatBufferingEnd);
+        notify->setInt32("what", kWhatResumeOnBufferingEnd);
         notify->post();
     }
 
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 67d9921..8809640 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -449,6 +449,59 @@
     return OK;
 }
 
+status_t NuMediaExtractor::appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer) {
+    int32_t numPageSamples;
+    if (!info->mSample->meta_data()->findInt32(
+            kKeyValidSamples, &numPageSamples)) {
+        numPageSamples = -1;
+    }
+
+    memcpy((uint8_t *)buffer->data() + info->mSample->range_length(),
+           &numPageSamples,
+           sizeof(numPageSamples));
+
+    uint32_t type;
+    const void *data;
+    size_t size, size2;
+    if (info->mSample->meta_data()->findData(kKeyEncryptedSizes, &type, &data, &size)) {
+        // Signal numPageSamples (a plain int32_t) is appended at the end,
+        // i.e. sizeof(numPageSamples) plain bytes + 0 encrypted bytes
+        if (SIZE_MAX - size < sizeof(int32_t)) {
+            return -ENOMEM;
+        }
+
+        size_t newSize = size + sizeof(int32_t);
+        sp<ABuffer> abuf = new ABuffer(newSize);
+        uint8_t *adata = static_cast<uint8_t *>(abuf->data());
+        if (adata == NULL) {
+            return -ENOMEM;
+        }
+
+        // append 0 to encrypted sizes
+        int32_t zero = 0;
+        memcpy(adata, data, size);
+        memcpy(adata + size, &zero, sizeof(zero));
+        info->mSample->meta_data()->setData(kKeyEncryptedSizes, type, adata, newSize);
+
+        if (info->mSample->meta_data()->findData(kKeyPlainSizes, &type, &data, &size2)) {
+            if (size2 != size) {
+                return ERROR_MALFORMED;
+            }
+            memcpy(adata, data, size);
+        } else {
+            // if sample meta data does not include plain size array, assume filled with zeros,
+            // i.e. entire buffer is encrypted
+            memset(adata, 0, size);
+        }
+        // append sizeof(numPageSamples) to plain sizes.
+        int32_t int32Size = sizeof(numPageSamples);
+        memcpy(adata + size, &int32Size, sizeof(int32Size));
+        info->mSample->meta_data()->setData(kKeyPlainSizes, type, adata, newSize);
+    }
+
+    return OK;
+}
+
 status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) {
     Mutex::Autolock autoLock(mLock);
 
@@ -478,21 +531,16 @@
 
     memcpy((uint8_t *)buffer->data(), src, info->mSample->range_length());
 
+    status_t err = OK;
     if (info->mTrackFlags & kIsVorbis) {
-        int32_t numPageSamples;
-        if (!info->mSample->meta_data()->findInt32(
-                    kKeyValidSamples, &numPageSamples)) {
-            numPageSamples = -1;
-        }
-
-        memcpy((uint8_t *)buffer->data() + info->mSample->range_length(),
-               &numPageSamples,
-               sizeof(numPageSamples));
+        err = appendVorbisNumPageSamples(info, buffer);
     }
 
-    buffer->setRange(0, sampleSize);
+    if (err == OK) {
+        buffer->setRange(0, sampleSize);
+    }
 
-    return OK;
+    return err;
 }
 
 status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) {
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 2a8b635..17fa239 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -461,6 +461,13 @@
         msg->setBuffer("csd-2", buffer);
     }
 
+    // TODO expose "crypto-key"/kKeyCryptoKey through public api
+    if (meta->findData(kKeyCryptoKey, &type, &data, &size)) {
+        sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
+        msg->setBuffer("crypto-key", buffer);
+        memcpy(buffer->data(), data, size);
+    }
+
     *format = msg;
 
     return OK;
diff --git a/media/libstagefright/matroska/Android.mk b/media/libstagefright/matroska/Android.mk
index 193408c..b0cbf08 100644
--- a/media/libstagefright/matroska/Android.mk
+++ b/media/libstagefright/matroska/Android.mk
@@ -7,6 +7,7 @@
 LOCAL_C_INCLUDES:= \
         $(TOP)/external/libvpx/libwebm \
         $(TOP)/frameworks/native/include/media/openmax \
+        $(TOP)/frameworks/av/media/libstagefright/include \
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 LOCAL_CLANG := true
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 82b471f..861bdc5 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -19,9 +19,11 @@
 #include <utils/Log.h>
 
 #include "MatroskaExtractor.h"
+#include "avc_utils.h"
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
@@ -144,12 +146,13 @@
     Type mType;
     bool mIsAudio;
     BlockIterator mBlockIter;
-    size_t mNALSizeLen;  // for type AVC
+    ssize_t mNALSizeLen;  // for type AVC
 
     List<MediaBuffer *> mPendingFrames;
 
     status_t advance();
 
+    status_t setWebmBlockCryptoInfo(MediaBuffer *mbuf);
     status_t readBlock();
     void clearPendingFrames();
 
@@ -213,7 +216,7 @@
       mBlockIter(mExtractor.get(),
                  mExtractor->mTracks.itemAt(index).mTrackNum,
                  index),
-      mNALSizeLen(0) {
+      mNALSizeLen(-1) {
     sp<MetaData> meta = mExtractor->mTracks.itemAt(index).mMeta;
 
     const char *mime;
@@ -227,13 +230,18 @@
         uint32_t dummy;
         const uint8_t *avcc;
         size_t avccSize;
-        CHECK(meta->findData(
-                    kKeyAVCC, &dummy, (const void **)&avcc, &avccSize));
-
-        CHECK_GE(avccSize, 5u);
-
-        mNALSizeLen = 1 + (avcc[4] & 3);
-        ALOGV("mNALSizeLen = %zu", mNALSizeLen);
+        int32_t nalSizeLen = 0;
+        if (meta->findInt32(kKeyNalLengthSize, &nalSizeLen)) {
+            if (nalSizeLen >= 0 && nalSizeLen <= 4) {
+                mNALSizeLen = nalSizeLen;
+            }
+        } else if (meta->findData(kKeyAVCC, &dummy, (const void **)&avcc, &avccSize)
+                && avccSize >= 5u) {
+            mNALSizeLen = 1 + (avcc[4] & 3);
+            ALOGV("mNALSizeLen = %zd", mNALSizeLen);
+        } else {
+            ALOGE("No mNALSizeLen");
+        }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
         mType = AAC;
     }
@@ -244,6 +252,10 @@
 }
 
 status_t MatroskaSource::start(MetaData * /* params */) {
+    if (mType == AVC && mNALSizeLen < 0) {
+        return ERROR_MALFORMED;
+    }
+
     mBlockIter.reset();
 
     return OK;
@@ -492,6 +504,9 @@
 }
 
 int64_t BlockIterator::blockTimeUs() const {
+    if (mCluster == NULL || mBlockEntry == NULL) {
+        return -1;
+    }
     return (mBlockEntry->GetBlock()->GetTime(mCluster) + 500ll) / 1000ll;
 }
 
@@ -511,6 +526,72 @@
     }
 }
 
+status_t MatroskaSource::setWebmBlockCryptoInfo(MediaBuffer *mbuf) {
+    if (mbuf->range_length() < 1 || mbuf->range_length() - 1 > INT32_MAX) {
+        // 1-byte signal
+        return ERROR_MALFORMED;
+    }
+
+    const uint8_t *data = (const uint8_t *)mbuf->data() + mbuf->range_offset();
+    bool blockEncrypted = data[0] & 0x1;
+    if (blockEncrypted && mbuf->range_length() < 9) {
+        // 1-byte signal + 8-byte IV
+        return ERROR_MALFORMED;
+    }
+
+    sp<MetaData> meta = mbuf->meta_data();
+    if (blockEncrypted) {
+        /*
+         *  0                   1                   2                   3
+         *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         *  |  Signal Byte  |                                               |
+         *  +-+-+-+-+-+-+-+-+             IV                                |
+         *  |                                                               |
+         *  |               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         *  |               |                                               |
+         *  |-+-+-+-+-+-+-+-+                                               |
+         *  :               Bytes 1..N of encrypted frame                   :
+         *  |                                                               |
+         *  |                                                               |
+         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         */
+        int32_t plainSizes[] = { 0 };
+        int32_t encryptedSizes[] = { static_cast<int32_t>(mbuf->range_length() - 9) };
+        uint8_t ctrCounter[16] = { 0 };
+        uint32_t type;
+        const uint8_t *keyId;
+        size_t keyIdSize;
+        sp<MetaData> trackMeta = mExtractor->mTracks.itemAt(mTrackIndex).mMeta;
+        CHECK(trackMeta->findData(kKeyCryptoKey, &type, (const void **)&keyId, &keyIdSize));
+        meta->setData(kKeyCryptoKey, 0, keyId, keyIdSize);
+        memcpy(ctrCounter, data + 1, 8);
+        meta->setData(kKeyCryptoIV, 0, ctrCounter, 16);
+        meta->setData(kKeyPlainSizes, 0, plainSizes, sizeof(plainSizes));
+        meta->setData(kKeyEncryptedSizes, 0, encryptedSizes, sizeof(encryptedSizes));
+        mbuf->set_range(9, mbuf->range_length() - 9);
+    } else {
+        /*
+         *  0                   1                   2                   3
+         *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         *  |  Signal Byte  |                                               |
+         *  +-+-+-+-+-+-+-+-+                                               |
+         *  :               Bytes 1..N of unencrypted frame                 :
+         *  |                                                               |
+         *  |                                                               |
+         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         */
+        int32_t plainSizes[] = { static_cast<int32_t>(mbuf->range_length() - 1) };
+        int32_t encryptedSizes[] = { 0 };
+        meta->setData(kKeyPlainSizes, 0, plainSizes, sizeof(plainSizes));
+        meta->setData(kKeyEncryptedSizes, 0, encryptedSizes, sizeof(encryptedSizes));
+        mbuf->set_range(1, mbuf->range_length() - 1);
+    }
+
+    return OK;
+}
+
 status_t MatroskaSource::readBlock() {
     CHECK(mPendingFrames.empty());
 
@@ -529,13 +610,19 @@
         mbuf->meta_data()->setInt64(kKeyTime, timeUs);
         mbuf->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey());
 
-        long n = frame.Read(mExtractor->mReader, (unsigned char *)mbuf->data());
-        if (n != 0) {
+        status_t err = frame.Read(mExtractor->mReader, static_cast<uint8_t *>(mbuf->data()));
+        if (err == OK
+                && mExtractor->mIsWebm
+                && mExtractor->mTracks.itemAt(mTrackIndex).mEncrypted) {
+            err = setWebmBlockCryptoInfo(mbuf);
+        }
+
+        if (err != OK) {
             mPendingFrames.clear();
 
             mBlockIter.advance();
             mbuf->release();
-            return ERROR_IO;
+            return err;
         }
 
         mPendingFrames.push_back(mbuf);
@@ -582,7 +669,7 @@
     MediaBuffer *frame = *mPendingFrames.begin();
     mPendingFrames.erase(mPendingFrames.begin());
 
-    if (mType != AVC) {
+    if (mType != AVC || mNALSizeLen == 0) {
         if (targetSampleTimeUs >= 0ll) {
             frame->meta_data()->setInt64(
                     kKeyTargetTime, targetSampleTimeUs);
@@ -598,6 +685,9 @@
     // followed by a corresponding number of bytes containing the fragment.
     // We output all these fragments into a single large buffer separated
     // by startcodes (0x00 0x00 0x00 0x01).
+    //
+    // When mNALSizeLen is 0, we assume the data is already in the format
+    // desired.
 
     const uint8_t *srcPtr =
         (const uint8_t *)frame->data() + frame->range_offset();
@@ -939,6 +1029,35 @@
     return OK;
 }
 
+status_t MatroskaExtractor::synthesizeAVCC(TrackInfo *trackInfo, size_t index) {
+    BlockIterator iter(this, trackInfo->mTrackNum, index);
+    if (iter.eos()) {
+        return ERROR_MALFORMED;
+    }
+
+    const mkvparser::Block *block = iter.block();
+    if (block->GetFrameCount() <= 0) {
+        return ERROR_MALFORMED;
+    }
+
+    const mkvparser::Block::Frame &frame = block->GetFrame(0);
+    sp<ABuffer> abuf = new ABuffer(frame.len);
+    long n = frame.Read(mReader, abuf->data());
+    if (n != 0) {
+        return ERROR_MALFORMED;
+    }
+
+    sp<MetaData> avcMeta = MakeAVCCodecSpecificData(abuf);
+    if (avcMeta == NULL) {
+        return ERROR_MALFORMED;
+    }
+
+    // Override the synthesized nal length size, which is arbitrary
+    avcMeta->setInt32(kKeyNalLengthSize, 0);
+    trackInfo->mMeta = avcMeta;
+    return OK;
+}
+
 void MatroskaExtractor::addTracks() {
     const mkvparser::Tracks *tracks = mSegment->GetTracks();
 
@@ -1051,10 +1170,31 @@
         meta->setInt64(kKeyDuration, (durationNs + 500) / 1000);
 
         mTracks.push();
-        TrackInfo *trackInfo = &mTracks.editItemAt(mTracks.size() - 1);
+        size_t n = mTracks.size() - 1;
+        TrackInfo *trackInfo = &mTracks.editItemAt(n);
         trackInfo->mTrackNum = track->GetNumber();
         trackInfo->mMeta = meta;
         trackInfo->mExtractor = this;
+
+        trackInfo->mEncrypted = false;
+        for(size_t i = 0; i < track->GetContentEncodingCount() && !trackInfo->mEncrypted; i++) {
+            const mkvparser::ContentEncoding *encoding = track->GetContentEncodingByIndex(i);
+            for(size_t j = 0; j < encoding->GetEncryptionCount(); j++) {
+                const mkvparser::ContentEncoding::ContentEncryption *encryption;
+                encryption = encoding->GetEncryptionByIndex(j);
+                meta->setData(kKeyCryptoKey, 0, encryption->key_id, encryption->key_id_len);
+                trackInfo->mEncrypted = true;
+                break;
+            }
+        }
+
+        if (!strcmp("V_MPEG4/ISO/AVC", codecID) && codecPrivateSize == 0) {
+            // Attempt to recover from AVC track without codec private data
+            err = synthesizeAVCC(trackInfo, n);
+            if (err != OK) {
+                mTracks.pop();
+            }
+        }
     }
 }
 
diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/libstagefright/matroska/MatroskaExtractor.h
index 120ef82..a1d6b00 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.h
+++ b/media/libstagefright/matroska/MatroskaExtractor.h
@@ -55,6 +55,7 @@
 
     struct TrackInfo {
         unsigned long mTrackNum;
+        bool mEncrypted;
         sp<MetaData> mMeta;
         const MatroskaExtractor *mExtractor;
         Vector<const mkvparser::CuePoint*> mCuePoints;
@@ -74,6 +75,7 @@
     bool mIsWebm;
     int64_t mSeekPreRollNs;
 
+    status_t synthesizeAVCC(TrackInfo *trackInfo, size_t index);
     void addTracks();
     void findThumbnails();
 
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 8e36065..5bb2dcd 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -359,6 +359,15 @@
     return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs));
 }
 
+EXPORT
+media_status_t AMediaCodec_setOutputSurface(AMediaCodec *mData, ANativeWindow* window) {
+    sp<Surface> surface = NULL;
+    if (window != NULL) {
+        surface = (Surface*) window;
+    }
+    return translate_error(mData->mCodec->setSurface(surface));
+}
+
 //EXPORT
 media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback,
         void *userdata) {