zoukankan      html  css  js  c++  java
  • stagefright框架 Video Playback的流程

    转自:1.http://blog.csdn.net/mfbao01/article/details/6234580

         2.http://disanji.net/2011/03/06/android-stagefright-datastream-awesomeplayer/

    在Android上,預設的多媒體框架(multimedia framework)是OpenCORE。OpenCORE的優點是兼顧了跨平台的移植性,而且已經過多方驗證,所以相對來說較為穩定;但是其缺點是過於龐大複雜,需要耗費相當多的時間去維護。從Android 2.0開始,Google引進了架構稍為簡潔的Stagefright,並且有逐漸取代OpenCORE的趨勢 (註1)。

    [圖1] Stagefright在Android多媒體架構中的位置。

    [圖2] Stagefright所涵蓋的模組 (註2)。

    以下我們就先來看看Stagefright是如何播放一個影片檔。

    Stagefright在Android中是以shared library的形式存在(libstagefright.so),其中的module -- AwesomePlayer可用來播放video/audio (註3)。AwesomePlayer提供許多API,可以讓上層的應用程式(Java/JNI)來呼叫,我們以一個簡單的程式來說明video playback的流程。

    在Java中,若要播放一個影片檔,我們會這樣寫:

    MediaPlayer mp = new MediaPlayer();
    mp.setDataSource(PATH_TO_FILE); ...... (1)
    mp.prepare(); ........................ (2)、(3)
    mp.start(); .......................... (4)

    在Stagefright中,則會看到相對應的處理;


    (1) 將檔案的絕對路徑指定給mUri

    status_t AwesomePlayer::setDataSource(const char* uri, ...)
    {
    return setDataSource_l(uri, ...);
    }

    status_t AwesomePlayer::setDataSource_l(const char* uri, ...)
    {
    mUri = uri;
    }
    代买中有一段注释
    //大概的意思就是说 这次setDataSource 并没有做什么实际的工作,实际的工作将在 finishSetDataSource_l 中做 以避免 调用setDataSource 阻塞

    // The actual work will be done during preparation in the call to   

    // ::finishSetDataSource_l to avoid blocking the calling thread in
    // setDataSource for any significant time.

    (2) 啟動mQueue,作為event handler

    status_t AwesomePlayer::prepare()
    {
    return prepare_l();
    }

    status_t AwesomePlayer::prepare_l()
    {
    prepareAsync_l();

    while (mFlags & PREPARING)
    {
    mPreparedCondition.wait(mLock);
    }
    }

    status_t AwesomePlayer::prepareAsync_l()
    {
    mQueue.start();

    mFlags |= PREPARING;
    mAsyncPrepareEvent = new AwesomeEvent(
    this
    &AwesomePlayer::onPrepareAsyncEvent);
    mQueue.postEvent(mAsyncPrepareEvent);
    }

    (3) onPrepareAsyncEvent被触发

    void AwesomePlayer::onPrepareAsyncEvent()
    {
    finishSetDataSource_l();

    initVideoDecoder(); ...... (3.3)
    initAudioDecoder();
    }

    status_t AwesomePlayer::finishSetDataSource_l()
    {

    .........判断是否是流文件.....
    本地文件 dataSource = DataSource::CreateFromURI(mUri.string(), ...);
    sp<MediaExtractor> extractor =
    MediaExtractor::Create(dataSource); ..... (3.1)

    return setDataSource_l(extractor); ......................... (3.2)
    }

    (3.1) 解析mUri所指定的檔案,並且根據其header來選擇對應的extractor
    (由数据源DataSource生成MediaExtractor)

    通过MediaExtractor::Create(dataSource)来实现。Create方法通过两步来生成相应的MediaExtractor:

    1、通过dataSource->sniff来探测数据类型

    2、生成相应的Extractor:

    sp<MediaExtractor> MediaExtractor::Create(const sp<DataSource> &source, ...)
    {
    source->sniff(&tmp, ...);
    mime = tmp.string();

    if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)

    || !strcasecmp(mime, "audio/mp4")) {

    return new MPEG4Extractor(source);

    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {

    return new MP3Extractor(source, meta);

    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)

    || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {

    return new AMRExtractor(source);

    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {

    return new WAVExtractor(source);

    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {

    return new OggExtractor(source);

    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {

    return new MatroskaExtractor(source);

    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {

    return new MPEG2TSExtractor(source);

    }
    }

    (3.2) 使用extractor對檔案做A/V的分離 (mVideoTrack/mAudioTrack)    生成mVideoTrack和mAudioTrack两个MediaSource。 

    status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor)
    {
    for (size_t i = 0; i < extractor->countTracks(); ++i)
    {
    sp<MetaData> meta = extractor->getTrackMetaData(i);

    CHECK(meta->findCString(kKeyMIMEType, &mime));

    if (!haveVideo && !strncasecmp(mime, "video/", 6))
    {
    setVideoSource(extractor->getTrack(i));
    haveVideo = true;
    }
    else if (!haveAudio && !strncasecmp(mime, "audio/", 6))
    {
    setAudioSource(extractor->getTrack(i));
    haveAudio = true;
    }
    }
    }

    void AwesomePlayer::setVideoSource(sp<MediaSource> source)
    {
    mVideoTrack = source;
    }

    (3.3) 根據mVideoTrack中的編碼類型來選擇video decoder (mVideoSource)

    到目前为止我们得到的这两个MediaSource只具有parser功能,没有decode功能。还需要对这两个MediaSource做进一步的包装:



    status_t AwesomePlayer::initVideoDecoder()
    {
    mVideoSource = OMXCodec::Create(mClient.interface(),
    mVideoTrack->getFormat(),
    false,
    mVideoTrack);
    }

    status_t AwesomePlayer::initAudioDecoder()
    {
    mAudioSource = OMXCodec::Create(
    mClient.interface(), mAudioTrack->getFormat(),
    false, // createEncoder
    mAudioTrack); mAudioSource = OMXCodec::Create(
    mClient.interface(), mAudioTrack->getFormat(),
    false, // createEncoder
    mAudioTrack);
    }
    这回又获取了两个MediaSource。它们具有parse和decode功能。

    (4) 將mVideoEvent放入mQueue中,開始解碼播放,並交由mVideoRenderer來畫出,当调用MediaSource.start()方法后,它的内部就会开始从数据源获取数据并解析,等到缓冲区满后便停止。在AwesomePlayer里就可以调用MediaSource的read方法读取解码后的数据。 ( mVideoSource->read ---mVideoTrack->read----视频文件)

     
    status_t AwesomePlayer::play()
    {
    return play_l();
    }

    status_t AwesomePlayer::play_l()
    {
    postVideoEvent_l();
    }

    void AwesomePlayer::postVideoEvent_l(int64_t delayUs)
    {
    mQueue.postEventWithDelay(mVideoEvent, delayUs);
    }

    void AwesomePlayer::onVideoEvent()
    {
    mVideoSource->read(&mVideoBuffer, &options);
    [Check Timestamp]
    mVideoRenderer->render(mVideoBuffer);

    postVideoEvent_l();
    }








     

  • 相关阅读:
    如何让自己的app尽量不被系统杀死
    linux常用命令-权限管理命令
    linux常用命令-用户管理命令
    linux常用命令-文件处理命令
    npm命令
    新技术新框架新工具选型原则
    tomcat启动命令行中文乱码
    docker命令
    tinkpad e450c 进入 BIOS
    基于Java服务的前后端分离解决跨域问题
  • 原文地址:https://www.cnblogs.com/soniclq/p/2334671.html
Copyright © 2011-2022 走看看