Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 873ebfb8 authored by Andreas Huber's avatar Andreas Huber Committed by Android Git Automerger
Browse files

am 223e4f73: Merge "Support for MP4V-ES packetization format according to...

am 223e4f73: Merge "Support for MP4V-ES packetization format according to RFC3016." into gingerbread

Merge commit '223e4f73' into gingerbread-plus-aosp

* commit '223e4f73':
  Support for MP4V-ES packetization format according to RFC3016.
parents 6694c71d 223e4f73
Loading
Loading
Loading
Loading
+166 −0
Original line number Original line Diff line number Diff line
/*
 * 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> &notify)
    : 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
+58 −0
Original line number Original line Diff line number Diff line
/*
 * 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> &notify);

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_
+186 −0
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@


#include <ctype.h>
#include <ctype.h>


#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -246,6 +247,161 @@ sp<ABuffer> MakeAACCodecSpecificData(const char *params) {
    return csd;
    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(
APacketSource::APacketSource(
        const sp<ASessionDescription> &sessionDesc, size_t index)
        const sp<ASessionDescription> &sessionDesc, size_t index)
    : mInitCheck(NO_INIT),
    : mInitCheck(NO_INIT),
@@ -351,6 +507,36 @@ APacketSource::APacketSource(
        if (sampleRate != 16000 || numChannels != 1) {
        if (sampleRate != 16000 || numChannels != 1) {
            mInitCheck = ERROR_UNSUPPORTED;
            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 {
    } else {
        mInitCheck = ERROR_UNSUPPORTED;
        mInitCheck = ERROR_UNSUPPORTED;
    }
    }
+2 −0
Original line number Original line Diff line number Diff line
@@ -321,6 +321,8 @@ status_t ARTPConnection::receive(StreamInfo *s, bool receiveRTP) {


    buffer->setRange(0, nbytes);
    buffer->setRange(0, nbytes);


    // LOG(INFO) << "received " << buffer->size() << " bytes.";

    status_t err;
    status_t err;
    if (receiveRTP) {
    if (receiveRTP) {
        err = parseRTP(s, buffer);
        err = parseRTP(s, buffer);
+4 −0
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@
#include "AAVCAssembler.h"
#include "AAVCAssembler.h"
#include "AH263Assembler.h"
#include "AH263Assembler.h"
#include "AMPEG4AudioAssembler.h"
#include "AMPEG4AudioAssembler.h"
#include "AMPEG4ElementaryAssembler.h"
#include "ASessionDescription.h"
#include "ASessionDescription.h"


#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ABuffer.h>
@@ -63,6 +64,9 @@ ARTPSource::ARTPSource(
        mAssembler = new AAMRAssembler(notify, false /* isWide */, params);
        mAssembler = new AAMRAssembler(notify, false /* isWide */, params);
    } else  if (!strncmp(desc.c_str(), "AMR-WB/", 7)) {
    } else  if (!strncmp(desc.c_str(), "AMR-WB/", 7)) {
        mAssembler = new AAMRAssembler(notify, true /* isWide */, params);
        mAssembler = new AAMRAssembler(notify, true /* isWide */, params);
    } else if (!strncmp(desc.c_str(), "MP4V-ES/", 8)) {
        mAssembler = new AMPEG4ElementaryAssembler(notify);
        mIssueFIRRequests = true;
    } else {
    } else {
        TRESPASS();
        TRESPASS();
    }
    }
Loading