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

Commit 358efe41 authored by Android (Google) Code Review's avatar Android (Google) Code Review
Browse files

Merge change 7332

* changes:
  Squashed commit of the following:
parents f8125962 e46b7be8
Loading
Loading
Loading
Loading
+66 −0
Original line number Diff line number Diff line
ifeq ($(BUILD_WITH_STAGEFRIGHT),true)

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
	stagefright.cpp

LOCAL_SHARED_LIBRARIES := \
	libstagefright

LOCAL_C_INCLUDES:= \
	frameworks/base/media/libstagefright \
	$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
        $(TOP)/external/opencore/android

LOCAL_CFLAGS += -Wno-multichar

LOCAL_MODULE:= stagefright

include $(BUILD_EXECUTABLE)

################################################################################

include $(CLEAR_VARS)

LOCAL_SRC_FILES:=         \
        record.cpp

LOCAL_SHARED_LIBRARIES := \
	libstagefright

LOCAL_C_INCLUDES:= \
	frameworks/base/media/libstagefright \
	$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
        $(TOP)/external/opencore/android

LOCAL_CFLAGS += -Wno-multichar

LOCAL_MODULE:= record

include $(BUILD_EXECUTABLE)

################################################################################

# include $(CLEAR_VARS)
# 
# LOCAL_SRC_FILES:=         \
#         play.cpp
# 
# LOCAL_SHARED_LIBRARIES := \
# 	libstagefright
# 
# LOCAL_C_INCLUDES:= \
# 	frameworks/base/media/libstagefright \
# 	$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
#         $(TOP)/external/opencore/android
# 
# LOCAL_CFLAGS += -Wno-multichar
# 
# LOCAL_MODULE:= play
# 
# include $(BUILD_EXECUTABLE)

endif
+71 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2009 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 ANDROID_WAVEWRITER_H_

#define ANDROID_WAVEWRITER_H_

namespace android {

class WaveWriter {
public:
    WaveWriter(const char *filename,
               uint16_t num_channels, uint32_t sampling_rate)
        : mFile(fopen(filename, "wb")),
          mTotalBytes(0) {
        fwrite("RIFFxxxxWAVEfmt \x10\x00\x00\x00\x01\x00", 1, 22, mFile); 
        write_u16(num_channels);
        write_u32(sampling_rate);
        write_u32(sampling_rate * num_channels * 2);
        write_u16(num_channels * 2);
        write_u16(16);
        fwrite("dataxxxx", 1, 8, mFile);
    }

    ~WaveWriter() {
        fseek(mFile, 40, SEEK_SET);
        write_u32(mTotalBytes);

        fseek(mFile, 4, SEEK_SET);
        write_u32(36 + mTotalBytes);

        fclose(mFile);
        mFile = NULL;
    }

    void Append(const void *data, size_t size) {
        fwrite(data, 1, size, mFile);
        mTotalBytes += size;
    }

private:
    void write_u16(uint16_t x) {
        fputc(x & 0xff, mFile);
        fputc(x >> 8, mFile);
    }

    void write_u32(uint32_t x) {
        write_u16(x & 0xffff);
        write_u16(x >> 16);
    }

    FILE *mFile;
    size_t mTotalBytes;
};

}  // namespace android

#endif  // ANDROID_WAVEWRITER_H_
+295 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2009 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 <binder/ProcessState.h>
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/TimedEventQueue.h>
#include <media/stagefright/MPEG4Extractor.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MmapSource.h>
#include <media/stagefright/OMXDecoder.h>

using namespace android;

struct NewPlayer {
    NewPlayer();
    ~NewPlayer();

    void setSource(const char *uri);
    void start();
    void pause();
    void stop();

private:
    struct PlayerEvent : public TimedEventQueue::Event {
        PlayerEvent(NewPlayer *player,
                    void (NewPlayer::*method)(int64_t realtime_us))
            : mPlayer(player),
              mMethod(method) {
        }

        virtual void fire(TimedEventQueue *queue, int64_t realtime_us) {
            (mPlayer->*mMethod)(realtime_us);
        }

    private:
        NewPlayer *mPlayer;
        void (NewPlayer::*mMethod)(int64_t realtime_us);

        PlayerEvent(const PlayerEvent &);
        PlayerEvent &operator=(const PlayerEvent &);
    };

    struct PlayVideoFrameEvent : public TimedEventQueue::Event {
        PlayVideoFrameEvent(NewPlayer *player, MediaBuffer *buffer)
            : mPlayer(player),
              mBuffer(buffer) {
        }

        virtual ~PlayVideoFrameEvent() {
            if (mBuffer != NULL) {
                mBuffer->release();
                mBuffer = NULL;
            }
        }

        virtual void fire(TimedEventQueue *queue, int64_t realtime_us) {
            mPlayer->onPlayVideoFrame(realtime_us, mBuffer);
            mBuffer = NULL;
        }

    private:
        NewPlayer *mPlayer;
        MediaBuffer *mBuffer;

        PlayVideoFrameEvent(const PlayVideoFrameEvent &);
        PlayVideoFrameEvent &operator=(const PlayVideoFrameEvent &);
    };

    OMXClient mClient;

    MPEG4Extractor *mExtractor;
    MediaSource *mAudioSource;
    OMXDecoder *mAudioDecoder;
    MediaSource *mVideoSource;
    OMXDecoder *mVideoDecoder;

    int32_t mVideoWidth, mVideoHeight;

    TimedEventQueue mQueue;
    wp<TimedEventQueue::Event> mPlayVideoFrameEvent;

    int64_t mMediaTimeUsStart;
    int64_t mRealTimeUsStart;

    void setAudioSource(MediaSource *source);
    void setVideoSource(MediaSource *source);

    int64_t approxRealTime(int64_t mediatime_us) const;

    void onStart(int64_t realtime_us);
    void onPause(int64_t realtime_us);
    void onFetchVideoFrame(int64_t realtime_us);
    void onPlayVideoFrame(int64_t realtime_us, MediaBuffer *buffer);

    static int64_t getMediaBufferTimeUs(MediaBuffer *buffer);

    NewPlayer(const NewPlayer &);
    NewPlayer &operator=(const NewPlayer &);
};

NewPlayer::NewPlayer()
    : mExtractor(NULL),
      mAudioSource(NULL),
      mAudioDecoder(NULL),
      mVideoSource(NULL),
      mVideoDecoder(NULL),
      mVideoWidth(0),
      mVideoHeight(0) {
    status_t err = mClient.connect();
    assert(err == OK);
}

NewPlayer::~NewPlayer() {
    stop();

    mClient.disconnect();
}

void NewPlayer::setSource(const char *uri) {
    stop();

    mExtractor = new MPEG4Extractor(new MmapSource(uri));

    int num_tracks;
    status_t err = mExtractor->countTracks(&num_tracks);
    assert(err == OK);

    for (int i = 0; i < num_tracks; ++i) {
        const sp<MetaData> meta = mExtractor->getTrackMetaData(i);
        assert(meta != NULL);

        const char *mime;
        if (!meta->findCString(kKeyMIMEType, &mime)) {
            continue;
        }

        bool is_audio = false;
        bool is_acceptable = false;
        if (!strncasecmp(mime, "audio/", 6)) {
            is_audio = true;
            is_acceptable = (mAudioSource == NULL);
        } else if (!strncasecmp(mime, "video/", 6)) {
            is_acceptable = (mVideoSource == NULL);
        }

        if (!is_acceptable) {
            continue;
        }

        MediaSource *source;
        if (mExtractor->getTrack(i, &source) != OK) {
            continue;
        }

        if (is_audio) {
            setAudioSource(source);
        } else {
            setVideoSource(source);
        }
    }
}

void NewPlayer::setAudioSource(MediaSource *source) {
    mAudioSource = source;

    sp<MetaData> meta = source->getFormat();

    mAudioDecoder = OMXDecoder::Create(&mClient, meta);
    mAudioDecoder->setSource(source);
}

void NewPlayer::setVideoSource(MediaSource *source) {
    mVideoSource = source;

    sp<MetaData> meta = source->getFormat();

    bool success = meta->findInt32(kKeyWidth, &mVideoWidth);
    assert(success);

    success = meta->findInt32(kKeyHeight, &mVideoHeight);
    assert(success);

    mVideoDecoder = OMXDecoder::Create(&mClient, meta);
    mVideoDecoder->setSource(source);
}

void NewPlayer::start() {
    mQueue.start();
    mQueue.postEvent(new PlayerEvent(this, &NewPlayer::onStart));
}

void NewPlayer::pause() {
    mQueue.postEvent(new PlayerEvent(this, &NewPlayer::onPause));
}

void NewPlayer::stop() {
    mQueue.stop();

    delete mVideoDecoder;
    mVideoDecoder = NULL;
    delete mVideoSource;
    mVideoSource = NULL;
    mVideoWidth = mVideoHeight = 0;

    delete mAudioDecoder;
    mAudioDecoder = NULL;
    delete mAudioSource;
    mAudioSource = NULL;

    delete mExtractor;
    mExtractor = NULL;
}

int64_t NewPlayer::approxRealTime(int64_t mediatime_us) const {
    return mRealTimeUsStart + (mediatime_us - mMediaTimeUsStart);
}

void NewPlayer::onStart(int64_t realtime_us) {
    mRealTimeUsStart = TimedEventQueue::getRealTimeUs();

    if (mVideoDecoder != NULL) {
        mQueue.postEvent(new PlayerEvent(this, &NewPlayer::onFetchVideoFrame));
    }
}

void NewPlayer::onFetchVideoFrame(int64_t realtime_us) {
    MediaBuffer *buffer;
    status_t err = mVideoDecoder->read(&buffer);
    assert(err == OK);

    int64_t mediatime_us = getMediaBufferTimeUs(buffer);

    sp<TimedEventQueue::Event> event = new PlayVideoFrameEvent(this, buffer);
    mPlayVideoFrameEvent = event;

    mQueue.postTimedEvent(event, approxRealTime(mediatime_us));
}

// static
int64_t NewPlayer::getMediaBufferTimeUs(MediaBuffer *buffer) {
    int32_t units, scale;
    bool success =
        buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
    assert(success);
    success =
        buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
    assert(success);

    return (int64_t)units * 1000000 / scale;
}

void NewPlayer::onPlayVideoFrame(int64_t realtime_us, MediaBuffer *buffer) {
    LOGI("playing video frame (mediatime: %.2f sec)\n",
         getMediaBufferTimeUs(buffer) / 1E6);
    fflush(stdout);

    buffer->release();
    buffer = NULL;

    mQueue.postEvent(new PlayerEvent(this, &NewPlayer::onFetchVideoFrame));
}

void NewPlayer::onPause(int64_t realtime_us) {
}

int main(int argc, char **argv) {
    android::ProcessState::self()->startThreadPool();

    if (argc != 2) {
        fprintf(stderr, "usage: %s filename\n", argv[0]);
        return 1;
    }

    NewPlayer player;
    player.setSource(argv[1]);
    player.start();
    sleep(10);
    player.stop();

    return 0;
}
+181 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2009 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.
 */

#undef NDEBUG
#include <assert.h>

#include <binder/ProcessState.h>
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MPEG4Extractor.h>
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/MmapSource.h>
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/OMXDecoder.h>

using namespace android;

class DummySource : public MediaSource {
public:
    DummySource(int width, int height)
        : mSize((width * height * 3) / 2) {
        mGroup.add_buffer(new MediaBuffer(mSize));
    }

    virtual ::status_t getMaxSampleSize(size_t *max_size) {
        *max_size = mSize;
        return ::OK;
    }

    virtual ::status_t read(MediaBuffer **buffer) {
        ::status_t err = mGroup.acquire_buffer(buffer);
        if (err != ::OK) {
            return err;
        }

        char x = (char)((double)rand() / RAND_MAX * 255);
        memset((*buffer)->data(), x, mSize);
        (*buffer)->set_range(0, mSize);

        return ::OK;
    }

private:
    MediaBufferGroup mGroup;
    size_t mSize;

    DummySource(const DummySource &);
    DummySource &operator=(const DummySource &);
};

int main(int argc, char **argv) {
    android::ProcessState::self()->startThreadPool();

#if 1
    if (argc != 2) {
        fprintf(stderr, "usage: %s filename\n", argv[0]);
        return 1;
    }

    MPEG4Extractor extractor(new MmapSource(argv[1]));
    int num_tracks;
    assert(extractor.countTracks(&num_tracks) == ::OK);

    MediaSource *source = NULL;
    sp<MetaData> meta;
    for (int i = 0; i < num_tracks; ++i) {
        meta = extractor.getTrackMetaData(i);
        assert(meta.get() != NULL);

        const char *mime;
        if (!meta->findCString(kKeyMIMEType, &mime)) {
            continue;
        }

        if (strncasecmp(mime, "video/", 6)) {
            continue;
        }

        if (extractor.getTrack(i, &source) != ::OK) {
            source = NULL;
            continue;
        }
        break;
    }

    if (source == NULL) {
        fprintf(stderr, "Unable to find a suitable video track.\n");
        return 1;
    }

    OMXClient client;
    assert(client.connect() == android::OK);

    OMXDecoder *decoder = OMXDecoder::Create(&client, meta);
    decoder->setSource(source);

    int width, height;
    bool success = meta->findInt32(kKeyWidth, &width);
    success = success && meta->findInt32(kKeyHeight, &height);
    assert(success);

    sp<MetaData> enc_meta = new MetaData;
    // enc_meta->setCString(kKeyMIMEType, "video/3gpp");
    enc_meta->setCString(kKeyMIMEType, "video/mp4v-es");
    enc_meta->setInt32(kKeyWidth, width);
    enc_meta->setInt32(kKeyHeight, height);

    OMXDecoder *encoder = OMXDecoder::CreateEncoder(&client, enc_meta);

    encoder->setSource(decoder);
    // encoder->setSource(meta, new DummySource(width, height));

#if 1
    MPEG4Writer writer("/sdcard/output.mp4");
    writer.addSource(enc_meta, encoder);
    writer.start();
    sleep(120);
    writer.stop();
#else
    encoder->start();

    MediaBuffer *buffer;
    while (encoder->read(&buffer) == ::OK) {
        printf("got an output frame of size %d\n", buffer->range_length());

        buffer->release();
        buffer = NULL;
    }

    encoder->stop();
#endif

    delete encoder;
    encoder = NULL;

    delete decoder;
    decoder = NULL;

    client.disconnect();

    delete source;
    source = NULL;
#endif

#if 0
    CameraSource *source = CameraSource::Create();
    printf("source = %p\n", source);

    for (int i = 0; i < 100; ++i) {
        MediaBuffer *buffer;
        status_t err = source->read(&buffer);
        assert(err == OK);

        printf("got a frame, data=%p, size=%d\n",
               buffer->data(), buffer->range_length());

        buffer->release();
        buffer = NULL;
    }

    delete source;
    source = NULL;
#endif

    return 0;
}
+200 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2009 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 <sys/time.h>

#undef NDEBUG
#include <assert.h>

#include <pthread.h>
#include <stdlib.h>

#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/CachingDataSource.h>
#include <media/stagefright/ESDS.h>
#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaPlayerImpl.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MmapSource.h>
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/OMXDecoder.h>

#include "WaveWriter.h"

using namespace android;

////////////////////////////////////////////////////////////////////////////////

static bool convertToWav(
        OMXClient *client, const sp<MetaData> &meta, MediaSource *source) {
    printf("convertToWav\n");

    OMXDecoder *decoder = OMXDecoder::Create(client, meta);

    int32_t sampleRate;
    bool success = meta->findInt32(kKeySampleRate, &sampleRate);
    assert(success);

    int32_t numChannels;
    success = meta->findInt32(kKeyChannelCount, &numChannels);
    assert(success);

    const char *mime;
    success = meta->findCString(kKeyMIMEType, &mime);
    assert(success);

    if (!strcasecmp("audio/3gpp", mime)) {
        numChannels = 1;  // XXX
    }

    WaveWriter writer("/sdcard/Music/shoutcast.wav", numChannels, sampleRate);

    decoder->setSource(source);
    for (int i = 0; i < 100; ++i) {
        MediaBuffer *buffer;

        ::status_t err = decoder->read(&buffer);
        if (err != ::OK) {
            break;
        }

        writer.Append((const char *)buffer->data() + buffer->range_offset(),
                      buffer->range_length());

        buffer->release();
        buffer = NULL;
    }

    delete decoder;
    decoder = NULL;

    return true;
}

////////////////////////////////////////////////////////////////////////////////

static int64_t getNowUs() {
    struct timeval tv;
    gettimeofday(&tv, NULL);

    return (int64_t)tv.tv_usec + tv.tv_sec * 1000000;
}

int main(int argc, char **argv) {
    android::ProcessState::self()->startThreadPool();

    if (argc > 1 && !strcmp(argv[1], "--list")) {
        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder = sm->getService(String16("media.player"));
        sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);

        assert(service.get() != NULL);

        sp<IOMX> omx = service->createOMX();
        assert(omx.get() != NULL);

        List<String8> list;
        omx->list_nodes(&list);

        for (List<String8>::iterator it = list.begin();
             it != list.end(); ++it) {
            printf("%s\n", (*it).string());
        }

        return 0;
    }

#if 0
    MediaPlayerImpl player(argv[1]);
    player.play();

    sleep(10000);
#else
    DataSource::RegisterDefaultSniffers();

    OMXClient client;
    status_t err = client.connect();

    MmapSource *dataSource = new MmapSource(argv[1]);
    MediaExtractor *extractor = MediaExtractor::Create(dataSource);
    dataSource = NULL;

    int numTracks;
    err = extractor->countTracks(&numTracks);

    sp<MetaData> meta;
    int i;
    for (i = 0; i < numTracks; ++i) {
        meta = extractor->getTrackMetaData(i);

        const char *mime;
        meta->findCString(kKeyMIMEType, &mime);

        if (!strncasecmp(mime, "video/", 6)) {
            break;
        }
    }

    OMXDecoder *decoder = OMXDecoder::Create(&client, meta);

    if (decoder != NULL) {
        MediaSource *source;
        err = extractor->getTrack(i, &source);

        decoder->setSource(source);

        decoder->start();

        int64_t startTime = getNowUs();

        int n = 0;
        MediaBuffer *buffer;
        while ((err = decoder->read(&buffer)) == OK) {
            if ((++n % 16) == 0) {
                printf(".");
                fflush(stdout);
            }

            buffer->release();
            buffer = NULL;
        }
        decoder->stop();
        printf("\n");

        int64_t delay = getNowUs() - startTime;
        printf("avg. %.2f fps\n", n * 1E6 / delay);

        delete decoder;
        decoder = NULL;

        delete source;
        source = NULL;
    }

    delete extractor;
    extractor = NULL;

    client.disconnect();
#endif

    return 0;
}
Loading