diff options
author | Andreas Huber <andih@google.com> | 2010-08-19 10:56:15 -0700 |
---|---|---|
committer | Andreas Huber <andih@google.com> | 2010-08-19 11:18:35 -0700 |
commit | 62cb04d23642a2ea7c005f050494c8ef3c370dd3 (patch) | |
tree | bfdb74407e1203c04d360896f5c530c7ee830800 /media | |
parent | c0f7ec8134eca61752d23c10596dd211745642d9 (diff) | |
download | frameworks_av-62cb04d23642a2ea7c005f050494c8ef3c370dd3.zip frameworks_av-62cb04d23642a2ea7c005f050494c8ef3c370dd3.tar.gz frameworks_av-62cb04d23642a2ea7c005f050494c8ef3c370dd3.tar.bz2 |
Support for MP4V-ES packetization format according to RFC3016.
Change-Id: I5e182936c52f9eb80cdcf6132ead03705ee32d61
Diffstat (limited to 'media')
-rw-r--r-- | media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp | 166 | ||||
-rw-r--r-- | media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h | 58 | ||||
-rw-r--r-- | media/libstagefright/rtsp/APacketSource.cpp | 186 | ||||
-rw-r--r-- | media/libstagefright/rtsp/ARTPConnection.cpp | 2 | ||||
-rw-r--r-- | media/libstagefright/rtsp/ARTPSource.cpp | 4 | ||||
-rw-r--r-- | media/libstagefright/rtsp/Android.mk | 1 |
6 files changed, 417 insertions, 0 deletions
diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp new file mode 100644 index 0000000..7e633d7 --- /dev/null +++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2010 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 "AMPEG4ElementaryAssembler.h" + +#include "ARTPSource.h" + +#include <media/stagefright/foundation/ABuffer.h> +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/AMessage.h> +#include <media/stagefright/foundation/hexdump.h> + +#include <stdint.h> + +#define BE_VERBOSE 0 + +namespace android { + +// static +AMPEG4ElementaryAssembler::AMPEG4ElementaryAssembler(const sp<AMessage> ¬ify) + : mNotifyMsg(notify), + mAccessUnitRTPTime(0), + mNextExpectedSeqNoValid(false), + mNextExpectedSeqNo(0), + mAccessUnitDamaged(false) { +} + +AMPEG4ElementaryAssembler::~AMPEG4ElementaryAssembler() { +} + +ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::addPacket( + const sp<ARTPSource> &source) { + List<sp<ABuffer> > *queue = source->queue(); + + if (queue->empty()) { + return NOT_ENOUGH_DATA; + } + + if (mNextExpectedSeqNoValid) { + List<sp<ABuffer> >::iterator it = queue->begin(); + while (it != queue->end()) { + if ((uint32_t)(*it)->int32Data() >= mNextExpectedSeqNo) { + break; + } + + it = queue->erase(it); + } + + if (queue->empty()) { + return NOT_ENOUGH_DATA; + } + } + + sp<ABuffer> buffer = *queue->begin(); + + if (!mNextExpectedSeqNoValid) { + mNextExpectedSeqNoValid = true; + mNextExpectedSeqNo = (uint32_t)buffer->int32Data(); + } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) { +#if BE_VERBOSE + LOG(VERBOSE) << "Not the sequence number I expected"; +#endif + + return WRONG_SEQUENCE_NUMBER; + } + + uint32_t rtpTime; + CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); + + if (mPackets.size() > 0 && rtpTime != mAccessUnitRTPTime) { + submitAccessUnit(); + } + mAccessUnitRTPTime = rtpTime; + + mPackets.push_back(buffer); + // hexdump(buffer->data(), buffer->size()); + + queue->erase(queue->begin()); + ++mNextExpectedSeqNo; + + return OK; +} + +void AMPEG4ElementaryAssembler::submitAccessUnit() { + CHECK(!mPackets.empty()); + +#if BE_VERBOSE + LOG(VERBOSE) << "Access unit complete (" << mPackets.size() << " nal units)"; +#endif + + uint64_t ntpTime; + CHECK((*mPackets.begin())->meta()->findInt64( + "ntp-time", (int64_t *)&ntpTime)); + + size_t totalSize = 0; + for (List<sp<ABuffer> >::iterator it = mPackets.begin(); + it != mPackets.end(); ++it) { + totalSize += (*it)->size(); + } + + sp<ABuffer> accessUnit = new ABuffer(totalSize); + size_t offset = 0; + for (List<sp<ABuffer> >::iterator it = mPackets.begin(); + it != mPackets.end(); ++it) { + sp<ABuffer> nal = *it; + memcpy(accessUnit->data() + offset, nal->data(), nal->size()); + offset += nal->size(); + } + + accessUnit->meta()->setInt64("ntp-time", ntpTime); + +#if 0 + printf(mAccessUnitDamaged ? "X" : "."); + fflush(stdout); +#endif + + if (mAccessUnitDamaged) { + accessUnit->meta()->setInt32("damaged", true); + } + + mPackets.clear(); + mAccessUnitDamaged = false; + + sp<AMessage> msg = mNotifyMsg->dup(); + msg->setObject("access-unit", accessUnit); + msg->post(); +} + +ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::assembleMore( + const sp<ARTPSource> &source) { + AssemblyStatus status = addPacket(source); + if (status == MALFORMED_PACKET) { + mAccessUnitDamaged = true; + } + return status; +} + +void AMPEG4ElementaryAssembler::packetLost() { + CHECK(mNextExpectedSeqNoValid); + LOG(VERBOSE) << "packetLost (expected " << mNextExpectedSeqNo << ")"; + + ++mNextExpectedSeqNo; + + mAccessUnitDamaged = true; +} + +void AMPEG4ElementaryAssembler::onByeReceived() { + sp<AMessage> msg = mNotifyMsg->dup(); + msg->setInt32("eos", true); + msg->post(); +} + +} // namespace android diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h new file mode 100644 index 0000000..1566d00 --- /dev/null +++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2010 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 A_MPEG4_ELEM_ASSEMBLER_H_ + +#define A_MPEG4_ELEM_ASSEMBLER_H_ + +#include "ARTPAssembler.h" + +#include <utils/List.h> +#include <utils/RefBase.h> + +namespace android { + +struct ABuffer; +struct AMessage; + +struct AMPEG4ElementaryAssembler : public ARTPAssembler { + AMPEG4ElementaryAssembler(const sp<AMessage> ¬ify); + +protected: + virtual ~AMPEG4ElementaryAssembler(); + + virtual AssemblyStatus assembleMore(const sp<ARTPSource> &source); + virtual void onByeReceived(); + virtual void packetLost(); + +private: + sp<AMessage> mNotifyMsg; + + uint32_t mAccessUnitRTPTime; + bool mNextExpectedSeqNoValid; + uint32_t mNextExpectedSeqNo; + bool mAccessUnitDamaged; + List<sp<ABuffer> > mPackets; + + AssemblyStatus addPacket(const sp<ARTPSource> &source); + void submitAccessUnit(); + + DISALLOW_EVIL_CONSTRUCTORS(AMPEG4ElementaryAssembler); +}; + +} // namespace android + +#endif // A_MPEG4_ELEM_ASSEMBLER_H_ diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp index 353c746..8c56cb7 100644 --- a/media/libstagefright/rtsp/APacketSource.cpp +++ b/media/libstagefright/rtsp/APacketSource.cpp @@ -22,6 +22,7 @@ #include <ctype.h> +#include <media/stagefright/foundation/ABitReader.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> @@ -246,6 +247,161 @@ sp<ABuffer> MakeAACCodecSpecificData(const char *params) { return csd; } +static size_t GetSizeWidth(size_t x) { + size_t n = 1; + while (x > 127) { + ++n; + x >>= 7; + } + return n; +} + +static uint8_t *EncodeSize(uint8_t *dst, size_t x) { + while (x > 127) { + *dst++ = (x & 0x7f) | 0x80; + x >>= 7; + } + *dst++ = x; + return dst; +} + +static bool ExtractDimensionsFromVOLHeader( + const sp<ABuffer> &config, int32_t *width, int32_t *height) { + *width = 0; + *height = 0; + + const uint8_t *ptr = config->data(); + size_t offset = 0; + bool foundVOL = false; + while (offset + 3 < config->size()) { + if (memcmp("\x00\x00\x01", &ptr[offset], 3) + || (ptr[offset + 3] & 0xf0) != 0x20) { + ++offset; + continue; + } + + foundVOL = true; + break; + } + + if (!foundVOL) { + return false; + } + + ABitReader br(&ptr[offset + 4], config->size() - offset - 4); + br.skipBits(1); // random_accessible_vol + unsigned video_object_type_indication = br.getBits(8); + + CHECK_NE(video_object_type_indication, + 0x21u /* Fine Granularity Scalable */); + + unsigned video_object_layer_verid; + unsigned video_object_layer_priority; + if (br.getBits(1)) { + video_object_layer_verid = br.getBits(4); + video_object_layer_priority = br.getBits(3); + } + unsigned aspect_ratio_info = br.getBits(4); + if (aspect_ratio_info == 0x0f /* 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 + TRESPASS(); + } + } + unsigned video_object_layer_shape = br.getBits(2); + CHECK_EQ(video_object_layer_shape, 0x00u /* rectangular */); + + CHECK(br.getBits(1)); // marker_bit + unsigned vop_time_increment_resolution = br.getBits(16); + CHECK(br.getBits(1)); // marker_bit + + if (br.getBits(1)) { // fixed_vop_rate + // range [0..vop_time_increment_resolution) + + // vop_time_increment_resolution + // 2 => 0..1, 1 bit + // 3 => 0..2, 2 bits + // 4 => 0..3, 2 bits + // 5 => 0..4, 3 bits + // ... + + CHECK_GT(vop_time_increment_resolution, 0u); + --vop_time_increment_resolution; + + unsigned numBits = 0; + while (vop_time_increment_resolution > 0) { + ++numBits; + vop_time_increment_resolution >>= 1; + } + + br.skipBits(numBits); // fixed_vop_time_increment + } + + CHECK(br.getBits(1)); // marker_bit + unsigned video_object_layer_width = br.getBits(13); + CHECK(br.getBits(1)); // marker_bit + unsigned video_object_layer_height = br.getBits(13); + CHECK(br.getBits(1)); // marker_bit + + unsigned interlaced = br.getBits(1); + + *width = video_object_layer_width; + *height = video_object_layer_height; + + LOG(INFO) << "VOL dimensions = " << *width << "x" << *height; + + return true; +} + +sp<ABuffer> MakeMPEG4VideoCodecSpecificData( + const char *params, int32_t *width, int32_t *height) { + *width = 0; + *height = 0; + + AString val; + CHECK(GetAttribute(params, "config", &val)); + + sp<ABuffer> config = decodeHex(val); + CHECK(config != NULL); + + if (!ExtractDimensionsFromVOLHeader(config, width, height)) { + return NULL; + } + + size_t len1 = config->size() + GetSizeWidth(config->size()) + 1; + size_t len2 = len1 + GetSizeWidth(len1) + 1 + 13; + size_t len3 = len2 + GetSizeWidth(len2) + 1 + 3; + + sp<ABuffer> csd = new ABuffer(len3); + uint8_t *dst = csd->data(); + *dst++ = 0x03; + dst = EncodeSize(dst, len2 + 3); + *dst++ = 0x00; // ES_ID + *dst++ = 0x00; + *dst++ = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag + + *dst++ = 0x04; + dst = EncodeSize(dst, len1 + 13); + *dst++ = 0x01; // Video ISO/IEC 14496-2 Simple Profile + for (size_t i = 0; i < 12; ++i) { + *dst++ = 0x00; + } + + *dst++ = 0x05; + dst = EncodeSize(dst, config->size()); + memcpy(dst, config->data(), config->size()); + dst += config->size(); + + // hexdump(csd->data(), csd->size()); + + return csd; +} + APacketSource::APacketSource( const sp<ASessionDescription> &sessionDesc, size_t index) : mInitCheck(NO_INIT), @@ -351,6 +507,36 @@ APacketSource::APacketSource( if (sampleRate != 16000 || numChannels != 1) { mInitCheck = ERROR_UNSUPPORTED; } + } else if (!strncmp(desc.c_str(), "MP4V-ES/", 8)) { + mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); + + int32_t width, height; + if (!sessionDesc->getDimensions(index, PT, &width, &height)) { + width = -1; + height = -1; + } + + int32_t encWidth, encHeight; + sp<ABuffer> codecSpecificData = + MakeMPEG4VideoCodecSpecificData( + params.c_str(), &encWidth, &encHeight); + + if (codecSpecificData != NULL) { + mFormat->setData( + kKeyESDS, 0, + codecSpecificData->data(), codecSpecificData->size()); + + if (width < 0) { + width = encWidth; + height = encHeight; + } + } else if (width < 0) { + mInitCheck = ERROR_UNSUPPORTED; + return; + } + + mFormat->setInt32(kKeyWidth, width); + mFormat->setInt32(kKeyHeight, height); } else { mInitCheck = ERROR_UNSUPPORTED; } diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp index 469af3e..6816c45 100644 --- a/media/libstagefright/rtsp/ARTPConnection.cpp +++ b/media/libstagefright/rtsp/ARTPConnection.cpp @@ -321,6 +321,8 @@ status_t ARTPConnection::receive(StreamInfo *s, bool receiveRTP) { buffer->setRange(0, nbytes); + // LOG(INFO) << "received " << buffer->size() << " bytes."; + status_t err; if (receiveRTP) { err = parseRTP(s, buffer); diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp index 225f6e8..775c4ee 100644 --- a/media/libstagefright/rtsp/ARTPSource.cpp +++ b/media/libstagefright/rtsp/ARTPSource.cpp @@ -20,6 +20,7 @@ #include "AAVCAssembler.h" #include "AH263Assembler.h" #include "AMPEG4AudioAssembler.h" +#include "AMPEG4ElementaryAssembler.h" #include "ASessionDescription.h" #include <media/stagefright/foundation/ABuffer.h> @@ -63,6 +64,9 @@ ARTPSource::ARTPSource( mAssembler = new AAMRAssembler(notify, false /* isWide */, params); } else if (!strncmp(desc.c_str(), "AMR-WB/", 7)) { mAssembler = new AAMRAssembler(notify, true /* isWide */, params); + } else if (!strncmp(desc.c_str(), "MP4V-ES/", 8)) { + mAssembler = new AMPEG4ElementaryAssembler(notify); + mIssueFIRRequests = true; } else { TRESPASS(); } diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk index 7f3659f..ed16059 100644 --- a/media/libstagefright/rtsp/Android.mk +++ b/media/libstagefright/rtsp/Android.mk @@ -7,6 +7,7 @@ LOCAL_SRC_FILES:= \ AAVCAssembler.cpp \ AH263Assembler.cpp \ AMPEG4AudioAssembler.cpp \ + AMPEG4ElementaryAssembler.cpp \ APacketSource.cpp \ ARTPAssembler.cpp \ ARTPConnection.cpp \ |