Support CbYCrY -> RGB565 color conversion in IOMXRenderer.
diff --git a/include/media/stagefright/SoftwareRenderer.h b/include/media/stagefright/SoftwareRenderer.h
index 705b914..b61858c 100644
--- a/include/media/stagefright/SoftwareRenderer.h
+++ b/include/media/stagefright/SoftwareRenderer.h
@@ -18,6 +18,7 @@
 
 #define SOFTWARE_RENDERER_H_
 
+#include <OMX_Video.h>
 #include <media/stagefright/VideoRenderer.h>
 #include <utils/RefBase.h>
 
@@ -29,6 +30,7 @@
 class SoftwareRenderer : public VideoRenderer {
 public:
     SoftwareRenderer(
+            OMX_COLOR_FORMATTYPE colorFormat,
             const sp<ISurface> &surface,
             size_t displayWidth, size_t displayHeight,
             size_t decodedWidth, size_t decodedHeight);
@@ -39,6 +41,12 @@
             const void *data, size_t size, void *platformPrivate);
 
 private:
+    uint8_t *initClip();
+
+    void renderCbYCrY(const void *data, size_t size);
+    void renderYUV420Planar(const void *data, size_t size);
+
+    OMX_COLOR_FORMATTYPE mColorFormat;
     sp<ISurface> mISurface;
     size_t mDisplayWidth, mDisplayHeight;
     size_t mDecodedWidth, mDecodedHeight;
@@ -46,6 +54,8 @@
     sp<MemoryHeapBase> mMemoryHeap;
     int mIndex;
 
+    uint8_t *mClip;
+
     SoftwareRenderer(const SoftwareRenderer &);
     SoftwareRenderer &operator=(const SoftwareRenderer &);
 };
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 1e59b52..8b83dd6 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -609,6 +609,7 @@
     } else {
         LOGW("Using software renderer.");
         impl = new SoftwareRenderer(
+                colorFormat,
                 surface,
                 displayWidth, displayHeight,
                 encodedWidth, encodedHeight);
diff --git a/media/libstagefright/omx/SoftwareRenderer.cpp b/media/libstagefright/omx/SoftwareRenderer.cpp
index da97d55..a1c478f 100644
--- a/media/libstagefright/omx/SoftwareRenderer.cpp
+++ b/media/libstagefright/omx/SoftwareRenderer.cpp
@@ -27,17 +27,20 @@
 #define QCOM_YUV        0
 
 SoftwareRenderer::SoftwareRenderer(
+        OMX_COLOR_FORMATTYPE colorFormat,
         const sp<ISurface> &surface,
         size_t displayWidth, size_t displayHeight,
         size_t decodedWidth, size_t decodedHeight)
-    : mISurface(surface),
+    : mColorFormat(colorFormat),
+      mISurface(surface),
       mDisplayWidth(displayWidth),
       mDisplayHeight(displayHeight),
       mDecodedWidth(decodedWidth),
       mDecodedHeight(decodedHeight),
       mFrameSize(mDecodedWidth * mDecodedHeight * 2),  // RGB565
       mMemoryHeap(new MemoryHeapBase(2 * mFrameSize)),
-      mIndex(0) {
+      mIndex(0),
+      mClip(NULL) {
     CHECK(mISurface.get() != NULL);
     CHECK(mDecodedWidth > 0);
     CHECK(mDecodedHeight > 0);
@@ -55,29 +58,37 @@
 
 SoftwareRenderer::~SoftwareRenderer() {
     mISurface->unregisterBuffers();
+
+    delete[] mClip;
+    mClip = NULL;
 }
 
 void SoftwareRenderer::render(
         const void *data, size_t size, void *platformPrivate) {
+    switch (mColorFormat) {
+        case OMX_COLOR_FormatYUV420Planar:
+            return renderYUV420Planar(data, size);
+
+        case OMX_COLOR_FormatCbYCrY:
+            return renderCbYCrY(data, size);
+
+        default:
+        {
+            LOGW("Cannot render color format %ld", mColorFormat);
+            break;
+        }
+    }
+}
+
+void SoftwareRenderer::renderYUV420Planar(
+        const void *data, size_t size) {
     if (size != (mDecodedHeight * mDecodedWidth * 3) / 2) {
         LOGE("size is %d, expected %d",
                 size, (mDecodedHeight * mDecodedWidth * 3) / 2);
     }
     CHECK(size >= (mDecodedWidth * mDecodedHeight * 3) / 2);
 
-    static const signed kClipMin = -278;
-    static const signed kClipMax = 535;
-    static uint8_t kClip[kClipMax - kClipMin + 1];
-    static uint8_t *kAdjustedClip = &kClip[-kClipMin];
-
-    static bool clipInitialized = false;
-
-    if (!clipInitialized) {
-        for (signed i = kClipMin; i <= kClipMax; ++i) {
-            kClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i;
-        }
-        clipInitialized = true;
-    }
+    uint8_t *kAdjustedClip = initClip();
 
     size_t offset = mIndex * mFrameSize;
 
@@ -172,4 +183,78 @@
     mIndex = 1 - mIndex;
 }
 
+void SoftwareRenderer::renderCbYCrY(
+        const void *data, size_t size) {
+    if (size != (mDecodedHeight * mDecodedWidth * 2)) {
+        LOGE("size is %d, expected %d",
+                size, (mDecodedHeight * mDecodedWidth * 2));
+    }
+    CHECK(size >= (mDecodedWidth * mDecodedHeight * 2));
+
+    uint8_t *kAdjustedClip = initClip();
+
+    size_t offset = mIndex * mFrameSize;
+    void *dst = (uint8_t *)mMemoryHeap->getBase() + offset;
+    uint32_t *dst_ptr = (uint32_t *)dst;
+
+    const uint8_t *src = (const uint8_t *)data;
+
+    for (size_t y = 0; y < mDecodedHeight; ++y) {
+        for (size_t x = 0; x < mDecodedWidth; x += 2) {
+            signed y1 = (signed)src[2 * x + 1] - 16;
+            signed y2 = (signed)src[2 * x + 3] - 16;
+            signed u = (signed)src[2 * x] - 128;
+            signed v = (signed)src[2 * x + 2] - 128;
+
+            signed u_b = u * 517;
+            signed u_g = -u * 100;
+            signed v_g = -v * 208;
+            signed v_r = v * 409;
+
+            signed tmp1 = y1 * 298;
+            signed b1 = (tmp1 + u_b) / 256;
+            signed g1 = (tmp1 + v_g + u_g) / 256;
+            signed r1 = (tmp1 + v_r) / 256;
+
+            signed tmp2 = y2 * 298;
+            signed b2 = (tmp2 + u_b) / 256;
+            signed g2 = (tmp2 + v_g + u_g) / 256;
+            signed r2 = (tmp2 + v_r) / 256;
+
+            uint32_t rgb1 =
+                ((kAdjustedClip[r1] >> 3) << 11)
+                | ((kAdjustedClip[g1] >> 2) << 5)
+                | (kAdjustedClip[b1] >> 3);
+
+            uint32_t rgb2 =
+                ((kAdjustedClip[r2] >> 3) << 11)
+                | ((kAdjustedClip[g2] >> 2) << 5)
+                | (kAdjustedClip[b2] >> 3);
+
+            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+        }
+
+        src += mDecodedWidth * 2;
+        dst_ptr += mDecodedWidth / 2;
+    }
+
+    mISurface->postBuffer(offset);
+    mIndex = 1 - mIndex;
+}
+
+uint8_t *SoftwareRenderer::initClip() {
+    static const signed kClipMin = -278;
+    static const signed kClipMax = 535;
+
+    if (mClip == NULL) {
+        mClip = new uint8_t[kClipMax - kClipMin + 1];
+
+        for (signed i = kClipMin; i <= kClipMax; ++i) {
+            mClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i;
+        }
+    }
+
+    return &mClip[-kClipMin];
+}
+
 }  // namespace android