我在一台手机上完成了264的硬编码,并打成RTP包,通过RTSP交互后,实时发送给另一台手机的Videoview,VideoView能收到并播放,但问题是,它需要有约5秒得延时才能播放,就是说我发送了5秒后,VideoView才有画面,图像质量倒是很不错,但5秒得延时实在太长了。开始我以为是我哪个环节没写对,但是我给VLC发就没有延时,所以我想VideoView因为是RTSP播放器,它可能需要缓冲5s的数据,但我也不敢肯定。请问做过VideoView的高手是否遇到同样的情况?是如何解决的? 

解决方案 »

  1.   

    结果就是VideoView能播放我发的264码流,但播放前会有5S的延时,我要处理这延时问题
      

  2.   

       Videoview内部是继承SurfaceView和使用MediaPlayer来实现的,用的是mMediaPlayer.prepareAsync()会缓冲数据但不会阻塞,缓冲完足够数据会调用OnPrepared。
      
       所以缓冲是必须的,你要用户界面友好点可以加个进度条(转圈的),然后再OnPrepared内关掉.
      

  3.   


    谢谢你的回答,很有帮助,我看到了MediaPlayer.prepareAsync的说明:Prepares the player for playback, asynchronously. After setting the datasource and the display surface, you need to either call prepare() or prepareAsync(). For streams, you should call prepareAsync(), which returns immediately, rather than blocking until enough data has been buffered.显然接收的是stream,它说returns immediately rather than blocking until enough data has been buffered是不是不需要缓冲的意思啊?
      

  4.   


    你的意思是关掉OnPrepare会关闭缓冲么?
      

  5.   

    这句是和prepare比较的 prepare是阻塞直到缓冲完函数才返回 prepareAsync是马上返回 缓冲是在后台进行 这时进入Preparing状态而不是马上进入Prepared状态。缓冲是为了看起来更流畅些要不看一下断一下也不好吧。
      

  6.   


    恩,我明白了,也就是说VideoView里面其实还是mediaplayer,按你的意思是它必须要缓冲数据,才能支持比如暂停,快进这样的操作。我用videoView的RTSP做流媒体接收是看好它硬解码这一块,无需移植解码库了,但是这个缓冲5秒实在无法忍受,不能实时就不用它了,移植解码库过来吧谢谢你的回复,再等一等就结贴了
      

  7.   


    还有个问题,如果提取出mediaplayer,单独编译,能否在源码里去掉缓冲这一部分,不知道你了不了解?
      

  8.   


    源码在frameworks\base\media\libmedia我看一下先mediaplayer的是模拟视频流播放的 要边下边播放 这里有个帖子
    http://www.360doc.com/content/11/0303/11/573136_97697574.shtml
      

  9.   


    找到了是在frameworks\base\media\libstagefright\AwesomePlayer.cpp内定义的void AwesomePlayer::onBufferingUpdate() {
        Mutex::Autolock autoLock(mLock);
        if (!mBufferingEventPending) {
            return;
        }
        mBufferingEventPending = false;    if (mCachedSource != NULL) {
            bool eos;
            size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);        if (eos) {
                notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
                if (mFlags & PREPARING) {
                    LOGV("cache has reached EOS, prepare is done.");
                    finishAsyncPrepare_l();
                }
            } else {
                int64_t bitrate;
                if (getBitrate(&bitrate)) {
                    size_t cachedSize = mCachedSource->cachedSize();
                    int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;                int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
                    if (percentage > 100) {
                        percentage = 100;
                    }                notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
                } else {
                    // We don't know the bitrate of the stream, use absolute size
                    // limits to maintain the cache.                const size_t kLowWaterMarkBytes = 40000;
                    const size_t kHighWaterMarkBytes = 200000;                if ((mFlags & PLAYING) && !eos
                            && (cachedDataRemaining < kLowWaterMarkBytes)) {
                        LOGI("cache is running low (< %d) , pausing.",
                             kLowWaterMarkBytes);
                        mFlags |= CACHE_UNDERRUN;
                        pause_l();
                        notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
                    } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
                        if (mFlags & CACHE_UNDERRUN) {
                            LOGI("cache has filled up (> %d), resuming.",
                                 kHighWaterMarkBytes);
                            mFlags &= ~CACHE_UNDERRUN;
                            play_l();
                            notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
                        } else if (mFlags & PREPARING) {
                            LOGV("cache has filled up (> %d), prepare is done",
                                 kHighWaterMarkBytes);
                            finishAsyncPrepare_l();
                        }
                    }
                }
            }
        }    int64_t cachedDurationUs;
        bool eos;
        if (getCachedDuration_l(&cachedDurationUs, &eos)) {
            if ((mFlags & PLAYING) && !eos
                    && (cachedDurationUs < kLowWaterMarkUs)) {
                LOGI("cache is running low (%.2f secs) , pausing.",
                     cachedDurationUs / 1E6);
                mFlags |= CACHE_UNDERRUN;
                pause_l();
                notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
            } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
                if (mFlags & CACHE_UNDERRUN) {
                    LOGI("cache has filled up (%.2f secs), resuming.",
                         cachedDurationUs / 1E6);
                    mFlags &= ~CACHE_UNDERRUN;
                    play_l();
                    notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
                } else if (mFlags & PREPARING) {
                    LOGV("cache has filled up (%.2f secs), prepare is done",
                         cachedDurationUs / 1E6);
                    finishAsyncPrepare_l();
                }
            }
        }    postBufferingEvent_l();
    }
      

  10.   

     系统默认使用固定大小来缓冲的 我这定义200000字节
                    const size_t kLowWaterMarkBytes = 40000;
                    const size_t kHighWaterMarkBytes = 200000;                if ((mFlags & PLAYING) && !eos
                            && (cachedDataRemaining < kLowWaterMarkBytes)) {
                        LOGI("cache is running low (< %d) , pausing.",
                             kLowWaterMarkBytes);
                        mFlags |= CACHE_UNDERRUN;
                        pause_l();
                        notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
                    } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
                        if (mFlags & CACHE_UNDERRUN) {
                            LOGI("cache has filled up (> %d), resuming.",
                                 kHighWaterMarkBytes);
                            mFlags &= ~CACHE_UNDERRUN;
                            play_l();
                            notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
                        } else if (mFlags & PREPARING) {
                            LOGV("cache has filled up (> %d), prepare is done",
                                 kHighWaterMarkBytes);
                            finishAsyncPrepare_l();
                        }
                    }
      

  11.   


    辛苦了,谢谢你,刚才看了这篇帖子,它的核心思想是区分了Streaming和Progress Download,按照它的定义,VideoView默认的需要缓冲方式是Progress Download,而我需要的是Streaming方式,他说如果在发送的mp4或者3gpp流里加入hint track,VideoView会自动解析出它是Streaming的,但是我发的不是文件流,我发的是264码流,里面没有hint信息,刚才在网上搜发现一篇论文,说法是,在RTSP协商的时候可通过SDP参数写hint信息,不知道可行否,我还得仔细看看
      

  12.   


    谢谢你的代码,如果没有其他办法了在考虑单独编译mediaplayer