am 936fff36: Merge change Ib64cab41 into eclair-mr2
Merge commit '936fff36882764ec031ae4fb8338273cc2abccd5' into eclair-mr2-plus-aosp * commit '936fff36882764ec031ae4fb8338273cc2abccd5': Split the ColorConverter off SoftwareRenderer, metadata support in stagefright.
This commit is contained in:
65
include/media/stagefright/ColorConverter.h
Normal file
65
include/media/stagefright/ColorConverter.h
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COLOR_CONVERTER_H_
|
||||||
|
|
||||||
|
#define COLOR_CONVERTER_H_
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <OMX_Video.h>
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
struct ColorConverter {
|
||||||
|
ColorConverter(OMX_COLOR_FORMATTYPE from, OMX_COLOR_FORMATTYPE to);
|
||||||
|
~ColorConverter();
|
||||||
|
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
|
void convert(
|
||||||
|
size_t width, size_t height,
|
||||||
|
const void *srcBits, size_t srcSkip,
|
||||||
|
void *dstBits, size_t dstSkip);
|
||||||
|
|
||||||
|
private:
|
||||||
|
OMX_COLOR_FORMATTYPE mSrcFormat, mDstFormat;
|
||||||
|
uint8_t *mClip;
|
||||||
|
|
||||||
|
uint8_t *initClip();
|
||||||
|
|
||||||
|
void convertCbYCrY(
|
||||||
|
size_t width, size_t height,
|
||||||
|
const void *srcBits, size_t srcSkip,
|
||||||
|
void *dstBits, size_t dstSkip);
|
||||||
|
|
||||||
|
void convertYUV420Planar(
|
||||||
|
size_t width, size_t height,
|
||||||
|
const void *srcBits, size_t srcSkip,
|
||||||
|
void *dstBits, size_t dstSkip);
|
||||||
|
|
||||||
|
void convertQCOMYUV420SemiPlanar(
|
||||||
|
size_t width, size_t height,
|
||||||
|
const void *srcBits, size_t srcSkip,
|
||||||
|
void *dstBits, size_t dstSkip);
|
||||||
|
|
||||||
|
ColorConverter(const ColorConverter &);
|
||||||
|
ColorConverter &operator=(const ColorConverter &);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace android
|
||||||
|
|
||||||
|
#endif // COLOR_CONVERTER_H_
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#define SOFTWARE_RENDERER_H_
|
#define SOFTWARE_RENDERER_H_
|
||||||
|
|
||||||
#include <OMX_Video.h>
|
#include <media/stagefright/ColorConverter.h>
|
||||||
#include <media/stagefright/VideoRenderer.h>
|
#include <media/stagefright/VideoRenderer.h>
|
||||||
#include <utils/RefBase.h>
|
#include <utils/RefBase.h>
|
||||||
|
|
||||||
@@ -41,13 +41,8 @@ public:
|
|||||||
const void *data, size_t size, void *platformPrivate);
|
const void *data, size_t size, void *platformPrivate);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t *initClip();
|
|
||||||
|
|
||||||
void renderCbYCrY(const void *data, size_t size);
|
|
||||||
void renderYUV420Planar(const void *data, size_t size);
|
|
||||||
void renderQCOMYUV420SemiPlanar(const void *data, size_t size);
|
|
||||||
|
|
||||||
OMX_COLOR_FORMATTYPE mColorFormat;
|
OMX_COLOR_FORMATTYPE mColorFormat;
|
||||||
|
ColorConverter mConverter;
|
||||||
sp<ISurface> mISurface;
|
sp<ISurface> mISurface;
|
||||||
size_t mDisplayWidth, mDisplayHeight;
|
size_t mDisplayWidth, mDisplayHeight;
|
||||||
size_t mDecodedWidth, mDecodedHeight;
|
size_t mDecodedWidth, mDecodedHeight;
|
||||||
@@ -55,8 +50,6 @@ private:
|
|||||||
sp<MemoryHeapBase> mMemoryHeap;
|
sp<MemoryHeapBase> mMemoryHeap;
|
||||||
int mIndex;
|
int mIndex;
|
||||||
|
|
||||||
uint8_t *mClip;
|
|
||||||
|
|
||||||
SoftwareRenderer(const SoftwareRenderer &);
|
SoftwareRenderer(const SoftwareRenderer &);
|
||||||
SoftwareRenderer &operator=(const SoftwareRenderer &);
|
SoftwareRenderer &operator=(const SoftwareRenderer &);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ LOCAL_SRC_FILES:= \
|
|||||||
|
|
||||||
ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true)
|
ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true)
|
||||||
|
|
||||||
LOCAL_SRC_FILES += \
|
LOCAL_SRC_FILES += \
|
||||||
StagefrightPlayer.cpp
|
StagefrightPlayer.cpp \
|
||||||
|
StagefrightMetadataRetriever.cpp
|
||||||
|
|
||||||
LOCAL_CFLAGS += -DBUILD_WITH_FULL_STAGEFRIGHT=1
|
LOCAL_CFLAGS += -DBUILD_WITH_FULL_STAGEFRIGHT=1
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include "VorbisMetadataRetriever.h"
|
#include "VorbisMetadataRetriever.h"
|
||||||
#include "MidiMetadataRetriever.h"
|
#include "MidiMetadataRetriever.h"
|
||||||
#include "MetadataRetrieverClient.h"
|
#include "MetadataRetrieverClient.h"
|
||||||
|
#include "StagefrightMetadataRetriever.h"
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
@@ -105,9 +106,15 @@ static sp<MediaMetadataRetrieverBase> createRetriever(player_type playerType)
|
|||||||
LOGV("create midi metadata retriever");
|
LOGV("create midi metadata retriever");
|
||||||
p = new MidiMetadataRetriever();
|
p = new MidiMetadataRetriever();
|
||||||
break;
|
break;
|
||||||
|
#if BUILD_WITH_FULL_STAGEFRIGHT
|
||||||
|
case STAGEFRIGHT_PLAYER:
|
||||||
|
LOGV("create StagefrightMetadataRetriever");
|
||||||
|
p = new StagefrightMetadataRetriever;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
// TODO:
|
// TODO:
|
||||||
// support for STAGEFRIGHT_PLAYER and TEST_PLAYER
|
// support for TEST_PLAYER
|
||||||
LOGE("player type %d is not supported", playerType);
|
LOGE("player type %d is not supported", playerType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
194
media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
Normal file
194
media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
**
|
||||||
|
** Copyright 2009, The Android Open Source Project
|
||||||
|
**
|
||||||
|
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
** you may not use this file except in compliance with the License.
|
||||||
|
** You may obtain a copy of the License at
|
||||||
|
**
|
||||||
|
** http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
**
|
||||||
|
** Unless required by applicable law or agreed to in writing, software
|
||||||
|
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
** See the License for the specific language governing permissions and
|
||||||
|
** limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//#define LOG_NDEBUG 0
|
||||||
|
#define LOG_TAG "StagefrightMetadataRetriever"
|
||||||
|
#include <utils/Log.h>
|
||||||
|
|
||||||
|
#include "StagefrightMetadataRetriever.h"
|
||||||
|
|
||||||
|
#include <media/stagefright/CachingDataSource.h>
|
||||||
|
#include <media/stagefright/ColorConverter.h>
|
||||||
|
#include <media/stagefright/DataSource.h>
|
||||||
|
#include <media/stagefright/HTTPDataSource.h>
|
||||||
|
#include <media/stagefright/MediaDebug.h>
|
||||||
|
#include <media/stagefright/MediaExtractor.h>
|
||||||
|
#include <media/stagefright/MetaData.h>
|
||||||
|
#include <media/stagefright/MmapSource.h>
|
||||||
|
#include <media/stagefright/OMXCodec.h>
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
StagefrightMetadataRetriever::StagefrightMetadataRetriever() {
|
||||||
|
LOGV("StagefrightMetadataRetriever()");
|
||||||
|
|
||||||
|
DataSource::RegisterDefaultSniffers();
|
||||||
|
CHECK_EQ(mClient.connect(), OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
|
||||||
|
LOGV("~StagefrightMetadataRetriever()");
|
||||||
|
mClient.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t StagefrightMetadataRetriever::setDataSource(const char *uri) {
|
||||||
|
LOGV("setDataSource(%s)", uri);
|
||||||
|
|
||||||
|
sp<DataSource> source;
|
||||||
|
if (!strncasecmp("file://", uri, 7)) {
|
||||||
|
sp<MmapSource> mmapSource = new MmapSource(uri + 7);
|
||||||
|
if (mmapSource->InitCheck() != OK) {
|
||||||
|
return ERROR_IO;
|
||||||
|
}
|
||||||
|
source = mmapSource;
|
||||||
|
} else if (!strncasecmp("http://", uri, 7)) {
|
||||||
|
source = new HTTPDataSource(uri);
|
||||||
|
source = new CachingDataSource(source, 64 * 1024, 10);
|
||||||
|
} else {
|
||||||
|
// Assume it's a filename.
|
||||||
|
sp<MmapSource> mmapSource = new MmapSource(uri);
|
||||||
|
if (mmapSource->InitCheck() != OK) {
|
||||||
|
return ERROR_IO;
|
||||||
|
}
|
||||||
|
source = mmapSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
mExtractor = MediaExtractor::Create(source);
|
||||||
|
|
||||||
|
return mExtractor.get() != NULL ? OK : UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t StagefrightMetadataRetriever::setDataSource(
|
||||||
|
int fd, int64_t offset, int64_t length) {
|
||||||
|
LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
|
||||||
|
|
||||||
|
mExtractor = MediaExtractor::Create(
|
||||||
|
new MmapSource(fd, offset, length));
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoFrame *StagefrightMetadataRetriever::captureFrame() {
|
||||||
|
LOGV("captureFrame");
|
||||||
|
|
||||||
|
if (mExtractor.get() == NULL) {
|
||||||
|
LOGE("no extractor.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t n = mExtractor->countTracks();
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
sp<MetaData> meta = mExtractor->getTrackMetaData(i);
|
||||||
|
|
||||||
|
const char *mime;
|
||||||
|
CHECK(meta->findCString(kKeyMIMEType, &mime));
|
||||||
|
|
||||||
|
if (!strncasecmp(mime, "video/", 6)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == n) {
|
||||||
|
LOGE("no video track found.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp<MediaSource> source = mExtractor->getTrack(i);
|
||||||
|
|
||||||
|
if (source.get() == NULL) {
|
||||||
|
LOGE("unable to instantiate video track.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp<MetaData> meta = source->getFormat();
|
||||||
|
|
||||||
|
sp<MediaSource> decoder =
|
||||||
|
OMXCodec::Create(
|
||||||
|
mClient.interface(), meta, false, source);
|
||||||
|
|
||||||
|
if (decoder.get() == NULL) {
|
||||||
|
LOGE("unable to instantiate video decoder.");
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder->start();
|
||||||
|
|
||||||
|
MediaBuffer *buffer;
|
||||||
|
status_t err = decoder->read(&buffer);
|
||||||
|
|
||||||
|
if (err != OK) {
|
||||||
|
CHECK_EQ(buffer, NULL);
|
||||||
|
|
||||||
|
LOGE("decoding frame failed.");
|
||||||
|
decoder->stop();
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGI("successfully decoded video frame.");
|
||||||
|
|
||||||
|
meta = decoder->getFormat();
|
||||||
|
|
||||||
|
int32_t width, height;
|
||||||
|
CHECK(meta->findInt32(kKeyWidth, &width));
|
||||||
|
CHECK(meta->findInt32(kKeyHeight, &height));
|
||||||
|
|
||||||
|
VideoFrame *frame = new VideoFrame;
|
||||||
|
frame->mWidth = width;
|
||||||
|
frame->mHeight = height;
|
||||||
|
frame->mDisplayWidth = width;
|
||||||
|
frame->mDisplayHeight = height;
|
||||||
|
frame->mSize = width * height * 2;
|
||||||
|
frame->mData = new uint8_t[frame->mSize];
|
||||||
|
|
||||||
|
int32_t srcFormat;
|
||||||
|
CHECK(meta->findInt32(kKeyColorFormat, &srcFormat));
|
||||||
|
|
||||||
|
ColorConverter converter(
|
||||||
|
(OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
|
||||||
|
CHECK(converter.isValid());
|
||||||
|
|
||||||
|
converter.convert(
|
||||||
|
width, height,
|
||||||
|
(const uint8_t *)buffer->data() + buffer->range_offset(),
|
||||||
|
0,
|
||||||
|
frame->mData, width * 2);
|
||||||
|
|
||||||
|
buffer->release();
|
||||||
|
buffer = NULL;
|
||||||
|
|
||||||
|
decoder->stop();
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
|
||||||
|
LOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO");
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) {
|
||||||
|
LOGV("extractMetadata %d (extractor: %s)",
|
||||||
|
keyCode, mExtractor.get() != NULL ? "YES" : "NO");
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace android
|
||||||
53
media/libmediaplayerservice/StagefrightMetadataRetriever.h
Normal file
53
media/libmediaplayerservice/StagefrightMetadataRetriever.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
**
|
||||||
|
** Copyright 2009, The Android Open Source Project
|
||||||
|
**
|
||||||
|
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
** you may not use this file except in compliance with the License.
|
||||||
|
** You may obtain a copy of the License at
|
||||||
|
**
|
||||||
|
** http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
**
|
||||||
|
** Unless required by applicable law or agreed to in writing, software
|
||||||
|
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
** See the License for the specific language governing permissions and
|
||||||
|
** limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STAGEFRIGHT_METADATA_RETRIEVER_H_
|
||||||
|
|
||||||
|
#define STAGEFRIGHT_METADATA_RETRIEVER_H_
|
||||||
|
|
||||||
|
#include <media/MediaMetadataRetrieverInterface.h>
|
||||||
|
|
||||||
|
#include <media/stagefright/OMXClient.h>
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
class MediaExtractor;
|
||||||
|
|
||||||
|
struct StagefrightMetadataRetriever : public MediaMetadataRetrieverInterface {
|
||||||
|
StagefrightMetadataRetriever();
|
||||||
|
virtual ~StagefrightMetadataRetriever();
|
||||||
|
|
||||||
|
virtual status_t setDataSource(const char *url);
|
||||||
|
virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
|
||||||
|
|
||||||
|
virtual VideoFrame *captureFrame();
|
||||||
|
virtual MediaAlbumArt *extractAlbumArt();
|
||||||
|
virtual const char *extractMetadata(int keyCode);
|
||||||
|
|
||||||
|
private:
|
||||||
|
OMXClient mClient;
|
||||||
|
sp<MediaExtractor> mExtractor;
|
||||||
|
|
||||||
|
StagefrightMetadataRetriever(const StagefrightMetadataRetriever &);
|
||||||
|
|
||||||
|
StagefrightMetadataRetriever &operator=(
|
||||||
|
const StagefrightMetadataRetriever &);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace android
|
||||||
|
|
||||||
|
#endif // STAGEFRIGHT_METADATA_RETRIEVER_H_
|
||||||
@@ -34,7 +34,10 @@ MmapSource::MmapSource(const char *filename)
|
|||||||
mBase(NULL),
|
mBase(NULL),
|
||||||
mSize(0) {
|
mSize(0) {
|
||||||
LOGV("MmapSource '%s'", filename);
|
LOGV("MmapSource '%s'", filename);
|
||||||
CHECK(mFd >= 0);
|
|
||||||
|
if (mFd < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
off_t size = lseek(mFd, 0, SEEK_END);
|
off_t size = lseek(mFd, 0, SEEK_END);
|
||||||
mSize = (size_t)size;
|
mSize = (size_t)size;
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ sp<OMXCodec> OMXCodec::Create(
|
|||||||
|
|
||||||
status_t err = omx->allocate_node(componentName, &node);
|
status_t err = omx->allocate_node(componentName, &node);
|
||||||
if (err == OK) {
|
if (err == OK) {
|
||||||
LOGI("Successfully allocated OMX node '%s'", componentName);
|
LOGV("Successfully allocated OMX node '%s'", componentName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,9 +321,10 @@ sp<OMXCodec> OMXCodec::Create(
|
|||||||
size -= length;
|
size -= length;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("AVC profile = %d (%s), level = %d",
|
LOGV("AVC profile = %d (%s), level = %d",
|
||||||
(int)profile, AVCProfileToString(profile), (int)level / 10);
|
(int)profile, AVCProfileToString(profile), (int)level / 10);
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (!strcmp(componentName, "OMX.TI.Video.Decoder")
|
if (!strcmp(componentName, "OMX.TI.Video.Decoder")
|
||||||
&& (profile != kAVCProfileBaseline || level > 39)) {
|
&& (profile != kAVCProfileBaseline || level > 39)) {
|
||||||
// This stream exceeds the decoder's capabilities.
|
// This stream exceeds the decoder's capabilities.
|
||||||
@@ -331,6 +332,7 @@ sp<OMXCodec> OMXCodec::Create(
|
|||||||
LOGE("Profile and/or level exceed the decoder's capabilities.");
|
LOGE("Profile and/or level exceed the decoder's capabilities.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
|
if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
|
||||||
@@ -440,7 +442,7 @@ status_t OMXCodec::setVideoPortFormatType(
|
|||||||
// CHECK_EQ(format.nIndex, index);
|
// CHECK_EQ(format.nIndex, index);
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
CODEC_LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
|
CODEC_LOGV("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
|
||||||
portIndex,
|
portIndex,
|
||||||
index, format.eCompressionFormat, format.eColorFormat);
|
index, format.eCompressionFormat, format.eColorFormat);
|
||||||
#endif
|
#endif
|
||||||
@@ -473,7 +475,7 @@ status_t OMXCodec::setVideoPortFormatType(
|
|||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
CODEC_LOGI("found a match.");
|
CODEC_LOGV("found a match.");
|
||||||
status_t err = mOMX->set_parameter(
|
status_t err = mOMX->set_parameter(
|
||||||
mNode, OMX_IndexParamVideoPortFormat,
|
mNode, OMX_IndexParamVideoPortFormat,
|
||||||
&format, sizeof(format));
|
&format, sizeof(format));
|
||||||
@@ -483,7 +485,7 @@ status_t OMXCodec::setVideoPortFormatType(
|
|||||||
|
|
||||||
void OMXCodec::setVideoInputFormat(
|
void OMXCodec::setVideoInputFormat(
|
||||||
const char *mime, OMX_U32 width, OMX_U32 height) {
|
const char *mime, OMX_U32 width, OMX_U32 height) {
|
||||||
CODEC_LOGI("setVideoInputFormat width=%ld, height=%ld", width, height);
|
CODEC_LOGV("setVideoInputFormat width=%ld, height=%ld", width, height);
|
||||||
|
|
||||||
OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
|
OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
|
||||||
if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
|
if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
|
||||||
@@ -543,7 +545,7 @@ void OMXCodec::setVideoInputFormat(
|
|||||||
CHECK_EQ(err, OK);
|
CHECK_EQ(err, OK);
|
||||||
|
|
||||||
def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
|
def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
|
||||||
CODEC_LOGI("Setting nBufferSize = %ld", def.nBufferSize);
|
CODEC_LOGV("Setting nBufferSize = %ld", def.nBufferSize);
|
||||||
|
|
||||||
CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
|
CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
|
||||||
|
|
||||||
@@ -559,7 +561,7 @@ void OMXCodec::setVideoInputFormat(
|
|||||||
|
|
||||||
void OMXCodec::setVideoOutputFormat(
|
void OMXCodec::setVideoOutputFormat(
|
||||||
const char *mime, OMX_U32 width, OMX_U32 height) {
|
const char *mime, OMX_U32 width, OMX_U32 height) {
|
||||||
CODEC_LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
|
CODEC_LOGV("setVideoOutputFormat width=%ld, height=%ld", width, height);
|
||||||
|
|
||||||
OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
|
OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
|
||||||
if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
|
if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ LOCAL_C_INCLUDES += $(TOP)/hardware/ti/omap3/liboverlay
|
|||||||
LOCAL_C_INCLUDES += $(JNI_H_INCLUDE)
|
LOCAL_C_INCLUDES += $(JNI_H_INCLUDE)
|
||||||
|
|
||||||
LOCAL_SRC_FILES:= \
|
LOCAL_SRC_FILES:= \
|
||||||
|
ColorConverter.cpp \
|
||||||
OMX.cpp \
|
OMX.cpp \
|
||||||
QComHardwareRenderer.cpp \
|
QComHardwareRenderer.cpp \
|
||||||
SoftwareRenderer.cpp \
|
SoftwareRenderer.cpp \
|
||||||
|
|||||||
297
media/libstagefright/omx/ColorConverter.cpp
Normal file
297
media/libstagefright/omx/ColorConverter.cpp
Normal file
@@ -0,0 +1,297 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <media/stagefright/ColorConverter.h>
|
||||||
|
#include <media/stagefright/MediaDebug.h>
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
|
||||||
|
|
||||||
|
ColorConverter::ColorConverter(
|
||||||
|
OMX_COLOR_FORMATTYPE from, OMX_COLOR_FORMATTYPE to)
|
||||||
|
: mSrcFormat(from),
|
||||||
|
mDstFormat(to),
|
||||||
|
mClip(NULL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorConverter::~ColorConverter() {
|
||||||
|
delete[] mClip;
|
||||||
|
mClip = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ColorConverter::isValid() const {
|
||||||
|
if (mDstFormat != OMX_COLOR_Format16bitRGB565) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mSrcFormat) {
|
||||||
|
case OMX_COLOR_FormatYUV420Planar:
|
||||||
|
case OMX_COLOR_FormatCbYCrY:
|
||||||
|
case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColorConverter::convert(
|
||||||
|
size_t width, size_t height,
|
||||||
|
const void *srcBits, size_t srcSkip,
|
||||||
|
void *dstBits, size_t dstSkip) {
|
||||||
|
CHECK_EQ(mDstFormat, OMX_COLOR_Format16bitRGB565);
|
||||||
|
|
||||||
|
switch (mSrcFormat) {
|
||||||
|
case OMX_COLOR_FormatYUV420Planar:
|
||||||
|
convertYUV420Planar(
|
||||||
|
width, height, srcBits, srcSkip, dstBits, dstSkip);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OMX_COLOR_FormatCbYCrY:
|
||||||
|
convertCbYCrY(
|
||||||
|
width, height, srcBits, srcSkip, dstBits, dstSkip);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
|
||||||
|
convertQCOMYUV420SemiPlanar(
|
||||||
|
width, height, srcBits, srcSkip, dstBits, dstSkip);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
CHECK(!"Should not be here. Unknown color conversion.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColorConverter::convertCbYCrY(
|
||||||
|
size_t width, size_t height,
|
||||||
|
const void *srcBits, size_t srcSkip,
|
||||||
|
void *dstBits, size_t dstSkip) {
|
||||||
|
CHECK_EQ(srcSkip, 0); // Doesn't really make sense for YUV formats.
|
||||||
|
CHECK(dstSkip >= width * 2);
|
||||||
|
CHECK((dstSkip & 3) == 0);
|
||||||
|
|
||||||
|
uint8_t *kAdjustedClip = initClip();
|
||||||
|
|
||||||
|
uint32_t *dst_ptr = (uint32_t *)dstBits;
|
||||||
|
|
||||||
|
const uint8_t *src = (const uint8_t *)srcBits;
|
||||||
|
|
||||||
|
for (size_t y = 0; y < height; ++y) {
|
||||||
|
for (size_t x = 0; x < width; 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 += width * 2;
|
||||||
|
dst_ptr += dstSkip / 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColorConverter::convertYUV420Planar(
|
||||||
|
size_t width, size_t height,
|
||||||
|
const void *srcBits, size_t srcSkip,
|
||||||
|
void *dstBits, size_t dstSkip) {
|
||||||
|
CHECK_EQ(srcSkip, 0); // Doesn't really make sense for YUV formats.
|
||||||
|
CHECK(dstSkip >= width * 2);
|
||||||
|
CHECK((dstSkip & 3) == 0);
|
||||||
|
|
||||||
|
uint8_t *kAdjustedClip = initClip();
|
||||||
|
|
||||||
|
uint32_t *dst_ptr = (uint32_t *)dstBits;
|
||||||
|
const uint8_t *src_y = (const uint8_t *)srcBits;
|
||||||
|
|
||||||
|
const uint8_t *src_u =
|
||||||
|
(const uint8_t *)src_y + width * height;
|
||||||
|
|
||||||
|
const uint8_t *src_v =
|
||||||
|
(const uint8_t *)src_u + (width / 2) * (height / 2);
|
||||||
|
|
||||||
|
for (size_t y = 0; y < height; ++y) {
|
||||||
|
for (size_t x = 0; x < width; x += 2) {
|
||||||
|
// B = 1.164 * (Y - 16) + 2.018 * (U - 128)
|
||||||
|
// G = 1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128)
|
||||||
|
// R = 1.164 * (Y - 16) + 1.596 * (V - 128)
|
||||||
|
|
||||||
|
// B = 298/256 * (Y - 16) + 517/256 * (U - 128)
|
||||||
|
// G = .................. - 208/256 * (V - 128) - 100/256 * (U - 128)
|
||||||
|
// R = .................. + 409/256 * (V - 128)
|
||||||
|
|
||||||
|
// min_B = (298 * (- 16) + 517 * (- 128)) / 256 = -277
|
||||||
|
// min_G = (298 * (- 16) - 208 * (255 - 128) - 100 * (255 - 128)) / 256 = -172
|
||||||
|
// min_R = (298 * (- 16) + 409 * (- 128)) / 256 = -223
|
||||||
|
|
||||||
|
// max_B = (298 * (255 - 16) + 517 * (255 - 128)) / 256 = 534
|
||||||
|
// max_G = (298 * (255 - 16) - 208 * (- 128) - 100 * (- 128)) / 256 = 432
|
||||||
|
// max_R = (298 * (255 - 16) + 409 * (255 - 128)) / 256 = 481
|
||||||
|
|
||||||
|
// clip range -278 .. 535
|
||||||
|
|
||||||
|
signed y1 = (signed)src_y[x] - 16;
|
||||||
|
signed y2 = (signed)src_y[x + 1] - 16;
|
||||||
|
|
||||||
|
signed u = (signed)src_u[x / 2] - 128;
|
||||||
|
signed v = (signed)src_v[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_y += width;
|
||||||
|
|
||||||
|
if (y & 1) {
|
||||||
|
src_u += width / 2;
|
||||||
|
src_v += width / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst_ptr += dstSkip / 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColorConverter::convertQCOMYUV420SemiPlanar(
|
||||||
|
size_t width, size_t height,
|
||||||
|
const void *srcBits, size_t srcSkip,
|
||||||
|
void *dstBits, size_t dstSkip) {
|
||||||
|
CHECK_EQ(srcSkip, 0); // Doesn't really make sense for YUV formats.
|
||||||
|
CHECK(dstSkip >= width * 2);
|
||||||
|
CHECK((dstSkip & 3) == 0);
|
||||||
|
|
||||||
|
uint8_t *kAdjustedClip = initClip();
|
||||||
|
|
||||||
|
uint32_t *dst_ptr = (uint32_t *)dstBits;
|
||||||
|
const uint8_t *src_y = (const uint8_t *)srcBits;
|
||||||
|
|
||||||
|
const uint8_t *src_u =
|
||||||
|
(const uint8_t *)src_y + width * height;
|
||||||
|
|
||||||
|
for (size_t y = 0; y < height; ++y) {
|
||||||
|
for (size_t x = 0; x < width; x += 2) {
|
||||||
|
signed y1 = (signed)src_y[x] - 16;
|
||||||
|
signed y2 = (signed)src_y[x + 1] - 16;
|
||||||
|
|
||||||
|
signed u = (signed)src_u[x & ~1] - 128;
|
||||||
|
signed v = (signed)src_u[(x & ~1) + 1] - 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[b1] >> 3) << 11)
|
||||||
|
| ((kAdjustedClip[g1] >> 2) << 5)
|
||||||
|
| (kAdjustedClip[r1] >> 3);
|
||||||
|
|
||||||
|
uint32_t rgb2 =
|
||||||
|
((kAdjustedClip[b2] >> 3) << 11)
|
||||||
|
| ((kAdjustedClip[g2] >> 2) << 5)
|
||||||
|
| (kAdjustedClip[r2] >> 3);
|
||||||
|
|
||||||
|
dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
|
||||||
|
}
|
||||||
|
|
||||||
|
src_y += width;
|
||||||
|
|
||||||
|
if (y & 1) {
|
||||||
|
src_u += width;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst_ptr += dstSkip / 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *ColorConverter::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
|
||||||
@@ -283,7 +283,7 @@ status_t OMX::allocate_node(const char *name, node_id *node) {
|
|||||||
&handle, const_cast<char *>(name), meta, &kCallbacks);
|
&handle, const_cast<char *>(name), meta, &kCallbacks);
|
||||||
|
|
||||||
if (err != OMX_ErrorNone) {
|
if (err != OMX_ErrorNone) {
|
||||||
LOGE("FAILED to allocate omx component '%s'", name);
|
LOGV("FAILED to allocate omx component '%s'", name);
|
||||||
|
|
||||||
delete meta;
|
delete meta;
|
||||||
meta = NULL;
|
meta = NULL;
|
||||||
|
|||||||
@@ -24,14 +24,13 @@
|
|||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
#define QCOM_YUV 0
|
|
||||||
|
|
||||||
SoftwareRenderer::SoftwareRenderer(
|
SoftwareRenderer::SoftwareRenderer(
|
||||||
OMX_COLOR_FORMATTYPE colorFormat,
|
OMX_COLOR_FORMATTYPE colorFormat,
|
||||||
const sp<ISurface> &surface,
|
const sp<ISurface> &surface,
|
||||||
size_t displayWidth, size_t displayHeight,
|
size_t displayWidth, size_t displayHeight,
|
||||||
size_t decodedWidth, size_t decodedHeight)
|
size_t decodedWidth, size_t decodedHeight)
|
||||||
: mColorFormat(colorFormat),
|
: mColorFormat(colorFormat),
|
||||||
|
mConverter(colorFormat, OMX_COLOR_Format16bitRGB565),
|
||||||
mISurface(surface),
|
mISurface(surface),
|
||||||
mDisplayWidth(displayWidth),
|
mDisplayWidth(displayWidth),
|
||||||
mDisplayHeight(displayHeight),
|
mDisplayHeight(displayHeight),
|
||||||
@@ -39,12 +38,12 @@ SoftwareRenderer::SoftwareRenderer(
|
|||||||
mDecodedHeight(decodedHeight),
|
mDecodedHeight(decodedHeight),
|
||||||
mFrameSize(mDecodedWidth * mDecodedHeight * 2), // RGB565
|
mFrameSize(mDecodedWidth * mDecodedHeight * 2), // RGB565
|
||||||
mMemoryHeap(new MemoryHeapBase(2 * mFrameSize)),
|
mMemoryHeap(new MemoryHeapBase(2 * mFrameSize)),
|
||||||
mIndex(0),
|
mIndex(0) {
|
||||||
mClip(NULL) {
|
|
||||||
CHECK(mISurface.get() != NULL);
|
CHECK(mISurface.get() != NULL);
|
||||||
CHECK(mDecodedWidth > 0);
|
CHECK(mDecodedWidth > 0);
|
||||||
CHECK(mDecodedHeight > 0);
|
CHECK(mDecodedHeight > 0);
|
||||||
CHECK(mMemoryHeap->heapID() >= 0);
|
CHECK(mMemoryHeap->heapID() >= 0);
|
||||||
|
CHECK(mConverter.isValid());
|
||||||
|
|
||||||
ISurface::BufferHeap bufferHeap(
|
ISurface::BufferHeap bufferHeap(
|
||||||
mDisplayWidth, mDisplayHeight,
|
mDisplayWidth, mDisplayHeight,
|
||||||
@@ -58,278 +57,19 @@ SoftwareRenderer::SoftwareRenderer(
|
|||||||
|
|
||||||
SoftwareRenderer::~SoftwareRenderer() {
|
SoftwareRenderer::~SoftwareRenderer() {
|
||||||
mISurface->unregisterBuffers();
|
mISurface->unregisterBuffers();
|
||||||
|
|
||||||
delete[] mClip;
|
|
||||||
mClip = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftwareRenderer::render(
|
void SoftwareRenderer::render(
|
||||||
const void *data, size_t size, void *platformPrivate) {
|
const void *data, size_t size, void *platformPrivate) {
|
||||||
static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
|
|
||||||
|
|
||||||
switch (mColorFormat) {
|
|
||||||
case OMX_COLOR_FormatYUV420Planar:
|
|
||||||
return renderYUV420Planar(data, size);
|
|
||||||
|
|
||||||
case OMX_COLOR_FormatCbYCrY:
|
|
||||||
return renderCbYCrY(data, size);
|
|
||||||
|
|
||||||
case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
|
|
||||||
return renderQCOMYUV420SemiPlanar(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);
|
|
||||||
|
|
||||||
uint8_t *kAdjustedClip = initClip();
|
|
||||||
|
|
||||||
size_t offset = mIndex * mFrameSize;
|
size_t offset = mIndex * mFrameSize;
|
||||||
|
|
||||||
void *dst = (uint8_t *)mMemoryHeap->getBase() + offset;
|
void *dst = (uint8_t *)mMemoryHeap->getBase() + offset;
|
||||||
|
|
||||||
uint32_t *dst_ptr = (uint32_t *)dst;
|
mConverter.convert(
|
||||||
|
mDecodedWidth, mDecodedHeight,
|
||||||
const uint8_t *src_y = (const uint8_t *)data;
|
data, 0, dst, 2 * mDecodedWidth);
|
||||||
|
|
||||||
const uint8_t *src_u =
|
|
||||||
(const uint8_t *)src_y + mDecodedWidth * mDecodedHeight;
|
|
||||||
|
|
||||||
#if !QCOM_YUV
|
|
||||||
const uint8_t *src_v =
|
|
||||||
(const uint8_t *)src_u + (mDecodedWidth / 2) * (mDecodedHeight / 2);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (size_t y = 0; y < mDecodedHeight; ++y) {
|
|
||||||
for (size_t x = 0; x < mDecodedWidth; x += 2) {
|
|
||||||
// B = 1.164 * (Y - 16) + 2.018 * (U - 128)
|
|
||||||
// G = 1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128)
|
|
||||||
// R = 1.164 * (Y - 16) + 1.596 * (V - 128)
|
|
||||||
|
|
||||||
// B = 298/256 * (Y - 16) + 517/256 * (U - 128)
|
|
||||||
// G = .................. - 208/256 * (V - 128) - 100/256 * (U - 128)
|
|
||||||
// R = .................. + 409/256 * (V - 128)
|
|
||||||
|
|
||||||
// min_B = (298 * (- 16) + 517 * (- 128)) / 256 = -277
|
|
||||||
// min_G = (298 * (- 16) - 208 * (255 - 128) - 100 * (255 - 128)) / 256 = -172
|
|
||||||
// min_R = (298 * (- 16) + 409 * (- 128)) / 256 = -223
|
|
||||||
|
|
||||||
// max_B = (298 * (255 - 16) + 517 * (255 - 128)) / 256 = 534
|
|
||||||
// max_G = (298 * (255 - 16) - 208 * (- 128) - 100 * (- 128)) / 256 = 432
|
|
||||||
// max_R = (298 * (255 - 16) + 409 * (255 - 128)) / 256 = 481
|
|
||||||
|
|
||||||
// clip range -278 .. 535
|
|
||||||
|
|
||||||
signed y1 = (signed)src_y[x] - 16;
|
|
||||||
signed y2 = (signed)src_y[x + 1] - 16;
|
|
||||||
|
|
||||||
#if QCOM_YUV
|
|
||||||
signed u = (signed)src_u[x & ~1] - 128;
|
|
||||||
signed v = (signed)src_u[(x & ~1) + 1] - 128;
|
|
||||||
#else
|
|
||||||
signed u = (signed)src_u[x / 2] - 128;
|
|
||||||
signed v = (signed)src_v[x / 2] - 128;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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_y += mDecodedWidth;
|
|
||||||
|
|
||||||
if (y & 1) {
|
|
||||||
#if QCOM_YUV
|
|
||||||
src_u += mDecodedWidth;
|
|
||||||
#else
|
|
||||||
src_u += mDecodedWidth / 2;
|
|
||||||
src_v += mDecodedWidth / 2;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
dst_ptr += mDecodedWidth / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
mISurface->postBuffer(offset);
|
mISurface->postBuffer(offset);
|
||||||
mIndex = 1 - mIndex;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoftwareRenderer::renderQCOMYUV420SemiPlanar(
|
|
||||||
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);
|
|
||||||
|
|
||||||
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_y = (const uint8_t *)data;
|
|
||||||
|
|
||||||
const uint8_t *src_u =
|
|
||||||
(const uint8_t *)src_y + mDecodedWidth * mDecodedHeight;
|
|
||||||
|
|
||||||
for (size_t y = 0; y < mDecodedHeight; ++y) {
|
|
||||||
for (size_t x = 0; x < mDecodedWidth; x += 2) {
|
|
||||||
signed y1 = (signed)src_y[x] - 16;
|
|
||||||
signed y2 = (signed)src_y[x + 1] - 16;
|
|
||||||
|
|
||||||
signed u = (signed)src_u[x & ~1] - 128;
|
|
||||||
signed v = (signed)src_u[(x & ~1) + 1] - 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[b1] >> 3) << 11)
|
|
||||||
| ((kAdjustedClip[g1] >> 2) << 5)
|
|
||||||
| (kAdjustedClip[r1] >> 3);
|
|
||||||
|
|
||||||
uint32_t rgb2 =
|
|
||||||
((kAdjustedClip[b2] >> 3) << 11)
|
|
||||||
| ((kAdjustedClip[g2] >> 2) << 5)
|
|
||||||
| (kAdjustedClip[r2] >> 3);
|
|
||||||
|
|
||||||
dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
|
|
||||||
}
|
|
||||||
|
|
||||||
src_y += mDecodedWidth;
|
|
||||||
|
|
||||||
if (y & 1) {
|
|
||||||
src_u += mDecodedWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
} // namespace android
|
||||||
|
|||||||
Reference in New Issue
Block a user