diff options
Diffstat (limited to 'media/libstagefright/Utils.cpp')
-rw-r--r-- | media/libstagefright/Utils.cpp | 300 |
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, ¶m); 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 |