summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/Utils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/Utils.cpp')
-rw-r--r--media/libstagefright/Utils.cpp300
1 files changed, 286 insertions, 14 deletions
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 0d9dc3a..489ccc3 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -35,6 +35,10 @@
#include <media/stagefright/Utils.h>
#include <media/AudioParameter.h>
+#include <stagefright/AVExtensions.h>
+#include <media/stagefright/FFMPEGSoftCodec.h>
+#include <media/stagefright/foundation/ABitReader.h>
+
namespace android {
uint16_t U16_AT(const uint8_t *ptr) {
@@ -70,7 +74,7 @@ uint64_t hton64(uint64_t x) {
return ((uint64_t)htonl(x & 0xffffffff) << 32) | htonl(x >> 32);
}
-static status_t copyNALUToABuffer(sp<ABuffer> *buffer, const uint8_t *ptr, size_t length) {
+status_t copyNALUToABuffer(sp<ABuffer> *buffer, const uint8_t *ptr, size_t length) {
if (((*buffer)->size() + 4 + length) > ((*buffer)->capacity() - (*buffer)->offset())) {
sp<ABuffer> tmpBuffer = new (std::nothrow) ABuffer((*buffer)->size() + 4 + length + 1024);
if (tmpBuffer.get() == NULL || tmpBuffer->base() == NULL) {
@@ -104,7 +108,7 @@ status_t convertMetaDataToMessage(
int avgBitRate;
if (meta->findInt32(kKeyBitRate, &avgBitRate)) {
- msg->setInt32("bit-rate", avgBitRate);
+ msg->setInt32("bitrate", avgBitRate);
}
int32_t isSync;
@@ -203,6 +207,11 @@ status_t convertMetaDataToMessage(
msg->setInt32("frame-rate", fps);
}
+ int32_t bitsPerSample;
+ if (meta->findInt32(kKeyBitsPerSample, &bitsPerSample)) {
+ msg->setInt32("bits-per-sample", bitsPerSample);
+ }
+
uint32_t type;
const void *data;
size_t size;
@@ -308,7 +317,7 @@ status_t convertMetaDataToMessage(
} else if (meta->findData(kKeyHVCC, &type, &data, &size)) {
const uint8_t *ptr = (const uint8_t *)data;
- if (size < 23 || ptr[0] != 1) { // configurationVersion == 1
+ if (size < 23) { // configurationVersion == 1
ALOGE("b/23680780");
return BAD_VALUE;
}
@@ -453,8 +462,17 @@ status_t convertMetaDataToMessage(
msg->setBuffer("csd-2", buffer);
}
+ AVUtils::get()->convertMetaDataToMessage(meta, &msg);
+
+ FFMPEGSoftCodec::convertMetaDataToMessageFF(meta, &msg);
*format = msg;
+#if 0
+ ALOGI("convertMetaDataToMessage from:");
+ meta->dumpToLog();
+ ALOGI(" to: %s", msg->debugString(0).c_str());
+#endif
+
return OK;
}
@@ -646,6 +664,11 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) {
if (msg->findInt32("is-adts", &isADTS)) {
meta->setInt32(kKeyIsADTS, isADTS);
}
+
+ int32_t bitsPerSample;
+ if (msg->findInt32("bits-per-sample", &bitsPerSample)) {
+ meta->setInt32(kKeyBitsPerSample, bitsPerSample);
+ }
}
int32_t maxInputSize;
@@ -705,8 +728,10 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) {
// XXX TODO add whatever other keys there are
+ FFMPEGSoftCodec::convertMessageToMetaDataFF(msg, meta);
+
#if 0
- ALOGI("converted %s to:", msg->debugString(0).c_str());
+ ALOGI("convertMessageToMetaData from %s to:", msg->debugString(0).c_str());
meta->dumpToLog();
#endif
}
@@ -747,13 +772,12 @@ status_t sendMetaDataToHal(sp<MediaPlayerBase::AudioSink>& sink,
if (meta->findInt32(kKeyBitRate, &bitRate)) {
param.addInt(String8(AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE), bitRate);
}
- if (meta->findInt32(kKeyEncoderDelay, &delaySamples)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES), delaySamples);
- }
- if (meta->findInt32(kKeyEncoderPadding, &paddingSamples)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES), paddingSamples);
- }
+ meta->findInt32(kKeyEncoderDelay, &delaySamples);
+ param.addInt(String8(AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES), delaySamples);
+ meta->findInt32(kKeyEncoderPadding, &paddingSamples);
+ param.addInt(String8(AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES), paddingSamples);
+ AVUtils::get()->sendMetaDataToHal(meta, &param);
ALOGV("sendMetaDataToHal: bitRate %d, sampleRate %d, chanMask %d,"
"delaySample %d, paddingSample %d", bitRate, sampleRate,
channelMask, delaySamples, paddingSamples);
@@ -775,6 +799,9 @@ static const struct mime_conv_t mimeLookup[] = {
{ MEDIA_MIMETYPE_AUDIO_AAC, AUDIO_FORMAT_AAC },
{ MEDIA_MIMETYPE_AUDIO_VORBIS, AUDIO_FORMAT_VORBIS },
{ MEDIA_MIMETYPE_AUDIO_OPUS, AUDIO_FORMAT_OPUS},
+#ifdef FLAC_OFFLOAD_ENABLED
+ { MEDIA_MIMETYPE_AUDIO_FLAC, AUDIO_FORMAT_FLAC},
+#endif
{ 0, AUDIO_FORMAT_INVALID }
};
@@ -789,7 +816,7 @@ const struct mime_conv_t* p = &mimeLookup[0];
++p;
}
- return BAD_VALUE;
+ return AVUtils::get()->mapMimeToAudioFormat(format, mime);
}
struct aac_format_conv_t {
@@ -843,18 +870,28 @@ bool canOffloadStream(const sp<MetaData>& meta, bool hasVideo,
} else {
ALOGV("Mime type \"%s\" mapped to audio_format %d", mime, info.format);
}
-
+ info.format = AVUtils::get()->updateAudioFormat(info.format, meta);
if (AUDIO_FORMAT_INVALID == info.format) {
// can't offload if we don't know what the source format is
ALOGE("mime type \"%s\" not a known audio format", mime);
return false;
}
+ if (AVUtils::get()->canOffloadAPE(meta) != true) {
+ return false;
+ }
+ ALOGV("Mime type \"%s\" mapped to audio_format %d", mime, info.format);
+
// Redefine aac format according to its profile
// Offloading depends on audio DSP capabilities.
int32_t aacaot = -1;
if (meta->findInt32(kKeyAACAOT, &aacaot)) {
- mapAACProfileToAudioFormat(info.format,(OMX_AUDIO_AACPROFILETYPE) aacaot);
+ bool isADTSSupported = false;
+ isADTSSupported = AVUtils::get()->mapAACProfileToAudioFormat(meta, info.format,
+ (OMX_AUDIO_AACPROFILETYPE) aacaot);
+ if (!isADTSSupported) {
+ mapAACProfileToAudioFormat(info.format,(OMX_AUDIO_AACPROFILETYPE) aacaot);
+ }
}
int32_t srate = -1;
@@ -864,7 +901,7 @@ bool canOffloadStream(const sp<MetaData>& meta, bool hasVideo,
info.sample_rate = srate;
int32_t cmask = 0;
- if (!meta->findInt32(kKeyChannelMask, &cmask)) {
+ if (!meta->findInt32(kKeyChannelMask, &cmask) || 0 == cmask) {
ALOGV("track of type '%s' does not publish channel mask", mime);
// Try a channel count instead
@@ -1017,5 +1054,240 @@ void readFromAMessage(
*sync = settings;
}
+audio_format_t getPCMFormat(const sp<AMessage> &format) {
+ int32_t bits = 16;
+ if (format->findInt32("bits-per-sample", &bits)) {
+ if (bits == 8)
+ return AUDIO_FORMAT_PCM_8_BIT;
+ if (bits == 24)
+ return AUDIO_FORMAT_PCM_32_BIT;
+ if (bits == 32)
+ return AUDIO_FORMAT_PCM_FLOAT;
+ }
+ return AUDIO_FORMAT_PCM_16_BIT;
+}
+
+void updateVideoTrackInfoFromESDS_MPEG4Video(sp<MetaData> meta) {
+ const char* mime = NULL;
+ if (meta != NULL && meta->findCString(kKeyMIMEType, &mime) &&
+ mime && !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!meta->findData(kKeyESDS, &type, &data, &size) || !data) {
+ ALOGW("ESDS atom is invalid");
+ return;
+ }
+
+ if (checkDPFromCodecSpecificData((const uint8_t*) data, size)) {
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4_DP);
+ }
+ }
+}
+
+bool checkDPFromCodecSpecificData(const uint8_t *data, size_t size) {
+ bool retVal = false;
+ size_t offset = 0, startCodeOffset = 0;
+ bool isStartCode = false;
+ const int kVolStartCode = 0x20;
+ const char kStartCode[] = "\x00\x00\x01";
+ // must contain at least 4 bytes for video_object_layer_start_code
+ const size_t kMinCsdSize = 4;
+
+ if (!data || (size < kMinCsdSize)) {
+ ALOGV("Invalid CSD (expected at least %zu bytes)", kMinCsdSize);
+ return retVal;
+ }
+
+ while (offset < size - 3) {
+ if ((data[offset + 3] & 0xf0) == kVolStartCode) {
+ if (!memcmp(&data[offset], kStartCode, 3)) {
+ startCodeOffset = offset;
+ isStartCode = true;
+ break;
+ }
+ }
+
+ offset++;
+ }
+
+ if (isStartCode) {
+ retVal = checkDPFromVOLHeader((const uint8_t*) &data[startCodeOffset],
+ (size - startCodeOffset));
+ }
+
+ return retVal;
+}
+
+bool checkDPFromVOLHeader(const uint8_t *data, size_t size) {
+ bool retVal = false;
+ // must contain at least 4 bytes for video_object_layer_start_code + 9 bits of data
+ const size_t kMinHeaderSize = 6;
+
+ if (!data || (size < kMinHeaderSize)) {
+ ALOGV("Invalid VOL header (expected at least %zu bytes)", kMinHeaderSize);
+ return false;
+ }
+
+ ALOGV("Checking for MPEG4 DP bit");
+ ABitReader br(&data[4], (size - 4));
+ br.skipBits(1); // random_accessible_vol
+
+ unsigned videoObjectTypeIndication = br.getBits(8);
+ if (videoObjectTypeIndication == 0x12u) {
+ ALOGW("checkDPFromVOLHeader: videoObjectTypeIndication:%u",
+ videoObjectTypeIndication);
+ return false;
+ }
+
+ unsigned videoObjectLayerVerid = 1;
+ if (br.getBits(1)) {
+ videoObjectLayerVerid = br.getBits(4);
+ br.skipBits(3); // video_object_layer_priority
+ ALOGV("checkDPFromVOLHeader: videoObjectLayerVerid:%u",
+ videoObjectLayerVerid);
+ }
+
+ if (br.getBits(4) == 0x0f) { // aspect_ratio_info
+ ALOGV("checkDPFromVOLHeader: extended PAR");
+ br.skipBits(8); // par_width
+ br.skipBits(8); // par_height
+ }
+
+ if (br.getBits(1)) { // vol_control_parameters
+ br.skipBits(2); // chroma_format
+ br.skipBits(1); // low_delay
+ if (br.getBits(1)) { // vbv_parameters
+ br.skipBits(15); // first_half_bit_rate
+ br.skipBits(1); // marker_bit
+ br.skipBits(15); // latter_half_bit_rate
+ br.skipBits(1); // marker_bit
+ br.skipBits(15); // first_half_vbv_buffer_size
+ br.skipBits(1); // marker_bit
+ br.skipBits(3); // latter_half_vbv_buffer_size
+ br.skipBits(11); // first_half_vbv_occupancy
+ br.skipBits(1); // marker_bit
+ br.skipBits(15); // latter_half_vbv_occupancy
+ br.skipBits(1); // marker_bit
+ }
+ }
+
+ unsigned videoObjectLayerShape = br.getBits(2);
+ if (videoObjectLayerShape != 0x00u /* rectangular */) {
+ ALOGV("checkDPFromVOLHeader: videoObjectLayerShape:%x",
+ videoObjectLayerShape);
+ return false;
+ }
+
+ br.skipBits(1); // marker_bit
+ unsigned vopTimeIncrementResolution = br.getBits(16);
+ br.skipBits(1); // marker_bit
+ if (br.getBits(1)) { // fixed_vop_rate
+ // range [0..vopTimeIncrementResolution)
+
+ // vopTimeIncrementResolution
+ // 2 => 0..1, 1 bit
+ // 3 => 0..2, 2 bits
+ // 4 => 0..3, 2 bits
+ // 5 => 0..4, 3 bits
+ // ...
+
+ if (vopTimeIncrementResolution <= 0u) {
+ return BAD_VALUE;
+ }
+
+ --vopTimeIncrementResolution;
+ unsigned numBits = 0;
+ while (vopTimeIncrementResolution > 0) {
+ ++numBits;
+ vopTimeIncrementResolution >>= 1;
+ }
+
+ br.skipBits(numBits); // fixed_vop_time_increment
+ }
+
+ br.skipBits(1); // marker_bit
+ br.skipBits(13); // video_object_layer_width
+ br.skipBits(1); // marker_bit
+ br.skipBits(13); // video_object_layer_height
+ br.skipBits(1); // marker_bit
+ br.skipBits(1); // interlaced
+ br.skipBits(1); // obmc_disable
+ unsigned spriteEnable = 0;
+ if (videoObjectLayerVerid == 1) {
+ spriteEnable = br.getBits(1);
+ } else {
+ spriteEnable = br.getBits(2);
+ }
+
+ if (spriteEnable == 0x1) { // static
+ int spriteWidth = br.getBits(13);
+ ALOGV("checkDPFromVOLHeader: spriteWidth:%d", spriteWidth);
+ br.skipBits(1) ; // marker_bit
+ br.skipBits(13); // sprite_height
+ br.skipBits(1); // marker_bit
+ br.skipBits(13); // sprite_left_coordinate
+ br.skipBits(1); // marker_bit
+ br.skipBits(13); // sprite_top_coordinate
+ br.skipBits(1); // marker_bit
+ br.skipBits(6); // no_of_sprite_warping_points
+ br.skipBits(2); // sprite_warping_accuracy
+ br.skipBits(1); // sprite_brightness_change
+ br.skipBits(1); // low_latency_sprite_enable
+ } else if (spriteEnable == 0x2) { // GMC
+ br.skipBits(6); // no_of_sprite_warping_points
+ br.skipBits(2); // sprite_warping_accuracy
+ br.skipBits(1); // sprite_brightness_change
+ }
+
+ if (videoObjectLayerVerid != 1
+ && videoObjectLayerShape != 0x0u) {
+ br.skipBits(1);
+ }
+
+ if (br.getBits(1)) { // not_8_bit
+ br.skipBits(4); // quant_precision
+ br.skipBits(4); // bits_per_pixel
+ }
+
+ if (videoObjectLayerShape == 0x3) {
+ br.skipBits(1);
+ br.skipBits(1);
+ br.skipBits(1);
+ }
+
+ if (br.getBits(1)) { // quant_type
+ if (br.getBits(1)) { // load_intra_quant_mat
+ unsigned IntraQuantMat = 1;
+ for (int i = 0; i < 64 && IntraQuantMat; i++) {
+ IntraQuantMat = br.getBits(8);
+ }
+ }
+
+ if (br.getBits(1)) { // load_non_intra_quant_matrix
+ unsigned NonIntraQuantMat = 1;
+ for (int i = 0; i < 64 && NonIntraQuantMat; i++) {
+ NonIntraQuantMat = br.getBits(8);
+ }
+ }
+ } /* quantType */
+
+ if (videoObjectLayerVerid != 1) {
+ unsigned quarterSample = br.getBits(1);
+ ALOGV("checkDPFromVOLHeader: quarterSample:%u",
+ quarterSample);
+ }
+
+ br.skipBits(1); // complexity_estimation_disable
+ br.skipBits(1); // resync_marker_disable
+ unsigned dataPartitioned = br.getBits(1);
+ if (dataPartitioned) {
+ retVal = true;
+ }
+
+ ALOGD("checkDPFromVOLHeader: DP:%u", dataPartitioned);
+ return retVal;
+}
+
} // namespace android