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

Commit faca94d1 authored by Andreas Huber's avatar Andreas Huber Committed by Android (Google) Code Review
Browse files

Merge "New HLS implementation supporting independent stream sources, audio-only streams"

parents 911c7451 14f7672b
Loading
Loading
Loading
Loading
+12 −40
Original line number Diff line number Diff line
@@ -30,8 +30,6 @@
#include <binder/ProcessState.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include "include/LiveSession.h"
#include "include/NuCachedSource2.h"
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/DataSource.h>
@@ -678,7 +676,6 @@ int main(int argc, char **argv) {
    gDisplayHistogram = false;

    sp<ALooper> looper;
    sp<LiveSession> liveSession;

    int res;
    while ((res = getopt(argc, argv, "han:lm:b:ptsrow:kxSTd:D:")) >= 0) {
@@ -961,9 +958,7 @@ int main(int argc, char **argv) {

        sp<DataSource> dataSource = DataSource::CreateFromURI(filename);

        if (strncasecmp(filename, "sine:", 5)
                && strncasecmp(filename, "httplive://", 11)
                && dataSource == NULL) {
        if (strncasecmp(filename, "sine:", 5) && dataSource == NULL) {
            fprintf(stderr, "Unable to create data source.\n");
            return 1;
        }
@@ -995,29 +990,7 @@ int main(int argc, char **argv) {
                mediaSources.push(mediaSource);
            }
        } else {
            sp<MediaExtractor> extractor;

            if (!strncasecmp("httplive://", filename, 11)) {
                String8 uri("http://");
                uri.append(filename + 11);

                if (looper == NULL) {
                    looper = new ALooper;
                    looper->start();
                }
                liveSession = new LiveSession(NULL /* notify */);
                looper->registerHandler(liveSession);

                liveSession->connect(uri.string());
                dataSource = liveSession->getDataSource();

                extractor =
                    MediaExtractor::Create(
                            dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);

                syncInfoPresent = false;
            } else {
                extractor = MediaExtractor::Create(dataSource);
            sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);

            if (extractor == NULL) {
                fprintf(stderr, "could not create extractor.\n");
@@ -1034,7 +1007,6 @@ int main(int argc, char **argv) {
                    syncInfoPresent = false;
                }
            }
            }

            size_t numTracks = extractor->countTracks();

+1 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ LOCAL_SHARED_LIBRARIES := \
    libsonivox                  \
    libstagefright              \
    libstagefright_foundation   \
    libstagefright_httplive     \
    libstagefright_omx          \
    libstagefright_wfd          \
    libutils                    \
+45 −95
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@

#include "HTTPLiveSource.h"

#include "ATSParser.h"
#include "AnotherPacketSource.h"
#include "LiveDataSource.h"
#include "LiveSession.h"
@@ -62,7 +61,10 @@ NuPlayer::HTTPLiveSource::HTTPLiveSource(
NuPlayer::HTTPLiveSource::~HTTPLiveSource() {
    if (mLiveSession != NULL) {
        mLiveSession->disconnect();
        mLiveSession.clear();

        mLiveLooper->stop();
        mLiveLooper.clear();
    }
}

@@ -76,112 +78,42 @@ void NuPlayer::HTTPLiveSource::prepareAsync() {
    mLiveSession = new LiveSession(
            notify,
            (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0,
            mUIDValid, mUID);
            mUIDValid,
            mUID);

    mLiveLooper->registerHandler(mLiveSession);

    mLiveSession->connect(
    mLiveSession->connectAsync(
            mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);

    mTSParser = new ATSParser;
}

void NuPlayer::HTTPLiveSource::start() {
}

sp<MetaData> NuPlayer::HTTPLiveSource::getFormatMeta(bool audio) {
    ATSParser::SourceType type =
        audio ? ATSParser::AUDIO : ATSParser::VIDEO;

    sp<AnotherPacketSource> source =
        static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());
sp<AMessage> NuPlayer::HTTPLiveSource::getFormat(bool audio) {
    sp<AMessage> format;
    status_t err = mLiveSession->getStreamFormat(
            audio ? LiveSession::STREAMTYPE_AUDIO
                  : LiveSession::STREAMTYPE_VIDEO,
            &format);

    if (source == NULL) {
    if (err != OK) {
        return NULL;
    }

    return source->getFormat();
    return format;
}

status_t NuPlayer::HTTPLiveSource::feedMoreTSData() {
    if (mFinalResult != OK) {
        return mFinalResult;
    }

    sp<LiveDataSource> source =
        static_cast<LiveDataSource *>(mLiveSession->getDataSource().get());

    for (int32_t i = 0; i < 50; ++i) {
        char buffer[188];
        ssize_t n = source->readAtNonBlocking(mOffset, buffer, sizeof(buffer));

        if (n == -EWOULDBLOCK) {
            break;
        } else if (n < 0) {
            if (n != ERROR_END_OF_STREAM) {
                ALOGI("input data EOS reached, error %ld", n);
            } else {
                ALOGI("input data EOS reached.");
            }
            mTSParser->signalEOS(n);
            mFinalResult = n;
            break;
        } else {
            if (buffer[0] == 0x00) {
                // XXX legacy

                uint8_t type = buffer[1];

                sp<AMessage> extra = new AMessage;

                if (type & 2) {
                    int64_t mediaTimeUs;
                    memcpy(&mediaTimeUs, &buffer[2], sizeof(mediaTimeUs));

                    extra->setInt64(IStreamListener::kKeyMediaTimeUs, mediaTimeUs);
                }

                mTSParser->signalDiscontinuity(
                        ((type & 1) == 0)
                            ? ATSParser::DISCONTINUITY_SEEK
                            : ATSParser::DISCONTINUITY_FORMATCHANGE,
                        extra);
            } else {
                status_t err = mTSParser->feedTSPacket(buffer, sizeof(buffer));

                if (err != OK) {
                    ALOGE("TS Parser returned error %d", err);
                    mTSParser->signalEOS(err);
                    mFinalResult = err;
                    break;
                }
            }

            mOffset += n;
        }
    }

    return OK;
}

status_t NuPlayer::HTTPLiveSource::dequeueAccessUnit(
        bool audio, sp<ABuffer> *accessUnit) {
    ATSParser::SourceType type =
        audio ? ATSParser::AUDIO : ATSParser::VIDEO;

    sp<AnotherPacketSource> source =
        static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());

    if (source == NULL) {
        return -EWOULDBLOCK;
    }

    status_t finalResult;
    if (!source->hasBufferAvailable(&finalResult)) {
        return finalResult == OK ? -EWOULDBLOCK : finalResult;
    }

    return source->dequeueAccessUnit(accessUnit);
    return mLiveSession->dequeueAccessUnit(
            audio ? LiveSession::STREAMTYPE_AUDIO
                  : LiveSession::STREAMTYPE_VIDEO,
            accessUnit);
}

status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) {
@@ -189,15 +121,7 @@ status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) {
}

status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs) {
    // We need to make sure we're not seeking until we have seen the very first
    // PTS timestamp in the whole stream (from the beginning of the stream).
    while (!mTSParser->PTSTimeDeltaEstablished() && feedMoreTSData() == OK) {
        usleep(100000);
    }

    mLiveSession->seekTo(seekTimeUs);

    return OK;
    return mLiveSession->seekTo(seekTimeUs);
}

void NuPlayer::HTTPLiveSource::onMessageReceived(const sp<AMessage> &msg) {
@@ -249,6 +173,32 @@ void NuPlayer::HTTPLiveSource::onSessionNotify(const sp<AMessage> &msg) {
            break;
        }

        case LiveSession::kWhatStreamsChanged:
        {
            uint32_t changedMask;
            CHECK(msg->findInt32(
                        "changedMask", (int32_t *)&changedMask));

            bool audio = changedMask & LiveSession::STREAMTYPE_AUDIO;
            bool video = changedMask & LiveSession::STREAMTYPE_VIDEO;

            sp<AMessage> reply;
            CHECK(msg->findMessage("reply", &reply));

            sp<AMessage> notify = dupNotify();
            notify->setInt32("what", kWhatQueueDecoderShutdown);
            notify->setInt32("audio", audio);
            notify->setInt32("video", video);
            notify->setMessage("reply", reply);
            notify->post();
            break;
        }

        case LiveSession::kWhatError:
        {
            break;
        }

        default:
            TRESPASS();
    }
+2 −6
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@

namespace android {

struct ATSParser;
struct LiveSession;

struct NuPlayer::HTTPLiveSource : public NuPlayer::Source {
@@ -37,18 +36,16 @@ struct NuPlayer::HTTPLiveSource : public NuPlayer::Source {
    virtual void prepareAsync();
    virtual void start();

    virtual status_t feedMoreTSData();

    virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
    virtual sp<AMessage> getFormat(bool audio);

    virtual status_t feedMoreTSData();
    virtual status_t getDuration(int64_t *durationUs);
    virtual status_t seekTo(int64_t seekTimeUs);

protected:
    virtual ~HTTPLiveSource();

    virtual sp<MetaData> getFormatMeta(bool audio);

    virtual void onMessageReceived(const sp<AMessage> &msg);

private:
@@ -70,7 +67,6 @@ private:
    off64_t mOffset;
    sp<ALooper> mLiveLooper;
    sp<LiveSession> mLiveSession;
    sp<ATSParser> mTSParser;

    void onSessionNotify(const sp<AMessage> &msg);

+81 −7
Original line number Diff line number Diff line
@@ -89,6 +89,38 @@ private:
    DISALLOW_EVIL_CONSTRUCTORS(SetSurfaceAction);
};

struct NuPlayer::ShutdownDecoderAction : public Action {
    ShutdownDecoderAction(bool audio, bool video)
        : mAudio(audio),
          mVideo(video) {
    }

    virtual void execute(NuPlayer *player) {
        player->performDecoderShutdown(mAudio, mVideo);
    }

private:
    bool mAudio;
    bool mVideo;

    DISALLOW_EVIL_CONSTRUCTORS(ShutdownDecoderAction);
};

struct NuPlayer::PostMessageAction : public Action {
    PostMessageAction(const sp<AMessage> &msg)
        : mMessage(msg) {
    }

    virtual void execute(NuPlayer *) {
        mMessage->post();
    }

private:
    sp<AMessage> mMessage;

    DISALLOW_EVIL_CONSTRUCTORS(PostMessageAction);
};

// Use this if there's no state necessary to save in order to execute
// the action.
struct NuPlayer::SimpleAction : public Action {
@@ -335,7 +367,8 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
            ALOGV("kWhatSetVideoNativeWindow");

            mDeferredActions.push_back(
                    new SimpleAction(&NuPlayer::performDecoderShutdown));
                    new ShutdownDecoderAction(
                        false /* audio */, true /* video */));

            sp<RefBase> obj;
            CHECK(msg->findObject("native-window", &obj));
@@ -712,7 +745,8 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
            ALOGV("kWhatReset");

            mDeferredActions.push_back(
                    new SimpleAction(&NuPlayer::performDecoderShutdown));
                    new ShutdownDecoderAction(
                        true /* audio */, true /* video */));

            mDeferredActions.push_back(
                    new SimpleAction(&NuPlayer::performReset));
@@ -1023,6 +1057,9 @@ void NuPlayer::notifyListener(int msg, int ext1, int ext2) {
}

void NuPlayer::flushDecoder(bool audio, bool needShutdown) {
    ALOGV("[%s] flushDecoder needShutdown=%d",
          audio ? "audio" : "video", needShutdown);

    if ((audio && mAudioDecoder == NULL) || (!audio && mVideoDecoder == NULL)) {
        ALOGI("flushDecoder %s without decoder present",
             audio ? "audio" : "video");
@@ -1173,20 +1210,29 @@ void NuPlayer::performDecoderFlush() {
    }
}

void NuPlayer::performDecoderShutdown() {
    ALOGV("performDecoderShutdown");
void NuPlayer::performDecoderShutdown(bool audio, bool video) {
    ALOGV("performDecoderShutdown audio=%d, video=%d", audio, video);

    if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
    if ((!audio || mAudioDecoder == NULL)
            && (!video || mVideoDecoder == NULL)) {
        return;
    }

    mTimeDiscontinuityPending = true;

    if (mAudioDecoder != NULL) {
    if (mFlushingAudio == NONE && (!audio || mAudioDecoder == NULL)) {
        mFlushingAudio = FLUSHED;
    }

    if (mFlushingVideo == NONE && (!video || mVideoDecoder == NULL)) {
        mFlushingVideo = FLUSHED;
    }

    if (audio && mAudioDecoder != NULL) {
        flushDecoder(true /* audio */, true /* needShutdown */);
    }

    if (mVideoDecoder != NULL) {
    if (video && mVideoDecoder != NULL) {
        flushDecoder(false /* audio */, true /* needShutdown */);
    }
}
@@ -1322,6 +1368,19 @@ void NuPlayer::onSourceNotify(const sp<AMessage> &msg) {
            break;
        }

        case Source::kWhatQueueDecoderShutdown:
        {
            int32_t audio, video;
            CHECK(msg->findInt32("audio", &audio));
            CHECK(msg->findInt32("video", &video));

            sp<AMessage> reply;
            CHECK(msg->findMessage("reply", &reply));

            queueDecoderShutdown(audio, video, reply);
            break;
        }

        default:
            TRESPASS();
    }
@@ -1355,4 +1414,19 @@ void NuPlayer::Source::onMessageReceived(const sp<AMessage> &msg) {
    TRESPASS();
}

void NuPlayer::queueDecoderShutdown(
        bool audio, bool video, const sp<AMessage> &reply) {
    ALOGI("queueDecoderShutdown audio=%d, video=%d", audio, video);

    mDeferredActions.push_back(
            new ShutdownDecoderAction(audio, video));

    mDeferredActions.push_back(
            new SimpleAction(&NuPlayer::performScanSources));

    mDeferredActions.push_back(new PostMessageAction(reply));

    processDeferredActions();
}

}  // namespace android
Loading