<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                前面介紹了Normal屬性顯示層中的第一類Layer,這里將介紹其中的第二類LayerBuffer。LayerBuffer會在視頻播放和攝像機預覽等場景中用到,就以Camera的preView(預覽)為例,來分析LayerBuffer的工作原理。 1. LayerBuffer的創建 先看LayerBuffer的創建,它通過SF的createPushBuffersSurfaceLocked得到,代碼如下所示: **SurfaceFlinger.cpp** ~~~ sp<LayerBaseClient> SurfaceFlinger::createPushBuffersSurfaceLocked( const sp<Client>& client, DisplayID display, int32_t id, uint32_t w, uint32_t h, uint32_t flags) { sp<LayerBuffer> layer = new LayerBuffer(this, display, client,id); layer->initStates(w, h, flags); addLayer_l(layer); returnlayer; } ~~~ LayerBuffer的派生關系,如圖8-30所示: :-: ![](http://img.blog.csdn.net/20150802163344531?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-30 LayerBuffer的派生關系示意圖 從上圖中可以發現: - LayerBuffer定義了一個內部類Source類,它有兩個派生類BufferSource和OverlaySource。根據它們的名字,可以猜測到Source代表數據的提供者。 * LayerBuffer中的mSurface其真實類型是SurfaceLayerBuffer。 LayerBuffer創建好了,不過該怎么用呢?和它相關的調用流程是怎樣的呢?下面來分析Camera。 2. Camera preView的分析 Camera是一個單獨的Service,全稱是CameraService,先看CameraService的registerPreviewBuffers函數。這個函數會做什么呢?代碼如下所示: **CameraService.cpp** ~~~ status_tCameraService::Client::registerPreviewBuffers() { int w, h; CameraParameters params(mHardware->getParameters()); params.getPreviewSize(&w, &h); /* ①mHardware代表Camera設備的HAL對象。本書討論CameraHardwareStub設備,它其實是 一個虛擬的設備,不過其代碼卻具有參考價值。 BufferHeap定義為ISurface的內部類,其實就是對IMemoryHeap的封裝 */ ISurface::BufferHeapbuffers(w, h, w, h, HAL_PIXEL_FORMAT_YCrCb_420_SP, mOrientation, 0, mHardware->getPreviewHeap()); //②調用SurfaceLayerBuffer的registerBuffers函數。 status_t ret = mSurface->registerBuffers(buffers); returnret; } ~~~ 上面代碼中列出了兩個關鍵點,逐一來分析它們。 (1)創建BufferHeap BufferHeap是ISurface定義的一個內部類,它的聲明如下所示: **ISurface.h** ~~~ classBufferHeap { public: ...... //使用這個構造函數 BufferHeap(uint32_t w, uint32_t h, int32_t hor_stride, int32_t ver_stride, PixelFormat format, const sp<IMemoryHeap>& heap); ...... ~BufferHeap(); uint32_t w; uint32_t h; int32_t hor_stride; int32_t ver_stride; PixelFormat format; uint32_t transform; uint32_t flags; sp<IMemoryHeap> heap; //heap指向真實的存儲對象 }; ~~~ 從上面代碼中可發現,BufferHeap基本上就是封裝了一個IMemoryHeap對象,根據我們對IMemoryHeap的了解,它應該包含了真實的存儲對象,這個值由CameraHardwareStub對象的getPreviewHeap得到,這個函數的代碼如下所示: **CameraHardwareStub.cpp** ~~~ sp<IMemoryHeap>CameraHardwareStub::getPreviewHeap() const { returnmPreviewHeap;//返回一個成員變量,它又是在哪創建的呢? } //上面的mPreivewHeap對象由initHeapLocked函數創建,該函數在HAL對象創建的時候被調用 void CameraHardwareStub::initHeapLocked() { ...... /* 創建一個MemoryHeapBase對象,大小是mPreviewFrameSize * kBufferCount,其中 kBufferCount為4。注意這是一段連續的緩沖。 */ mPreviewHeap= new MemoryHeapBase(mPreviewFrameSize * kBufferCount); //mBuffer為MemoryBase數組,元素為4 for (inti = 0; i < kBufferCount; i++) { mBuffers[i] = new MemoryBase(mPreviewHeap, i * mPreviewFrameSize, mPreviewFrameSize); } } ~~~ 從上面這段代碼中可以發現,CameraHardwareStub對象創建的用于preView的內存結構是按圖8-31所示的方式來組織的: :-: ![](http://img.blog.csdn.net/20150802163254109?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-31 CameraHardwareStub用于preView的內存結構圖 其中: - BufferHeap的heap變量指向一塊MemoryHeap,這就是mPreviewHeap。 - 在這塊MemoryHeap上構建了4個MemoryBase。 (2)registerBuffers的分析 BufferHeap準備好后,要調用ISurface的registerBuffers函數,ISurface在SF端的真實類型是SurfaceLayerBuffer,所以要直接看它的實現,代碼如下所示: **LayerBuffer.cpp** ~~~ status_t LayerBuffer::SurfaceLayerBuffer::registerBuffers( const ISurface::BufferHeap& buffers) { sp<LayerBuffer> owner(getOwner()); if (owner != 0) //調用外部類對象的registerBuffers,所以SurfaceLayerBuffer也是一個Proxy哦。 return owner->registerBuffers(buffers); returnNO_INIT; } //外部類是LayerBuffer,調用它的registerBuffers函數 status_t LayerBuffer::registerBuffers(constISurface::BufferHeap& buffers) { Mutex::Autolock _l(mLock); //創建數據的來源BufferSource,注意我們其實把MemoryHeap設置上去了 sp<BufferSource> source = new BufferSource(*this, buffers); status_t result = source->getStatus(); if(result == NO_ERROR) { mSource = source;//保存這個數據源為mSource。 } returnresult; } ~~~ BufferSource,曾在圖8-30中見識過,它內部有一個成員變量mBufferHeap指向傳入的buffers參數,所以registerBuffers過后,就得到了圖8-32: :-: ![](http://img.blog.csdn.net/20150802163322407?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-32 registerBuffers的結果示意圖 請注意上圖的箭頭指向,不論中間有多少層封裝,最終的數據存儲區域還是mPreivewHeap。 2.數據的傳輸 至此,Buffer在SF和Camera兩端都準備好了,那么數據是怎么從Camera傳遞到SF的呢?先來看數據源是怎么做的。 (1)數據傳輸的分析 CameraHardwareStub有一個preview線程,這個線程會做什么呢?代碼如下所示: **CameraHardwareStub.cpp** ~~~ //preview線程從Thread類派生,下面這個函數在threadLoop中循環調用 int CameraHardwareStub::previewThread() { mLock.lock(); //每次進來mCurrentPreviewFrame都會加1 ssize_t offset = mCurrentPreviewFrame * mPreviewFrameSize; sp<MemoryHeapBase> heap = mPreviewHeap; FakeCamera* fakeCamera = mFakeCamera;//虛擬的攝像機設備 //從mBuffers中取一塊內存,用于接收來自硬件的數據 sp<MemoryBase>buffer = mBuffers[mCurrentPreviewFrame]; mLock.unlock(); if(buffer != 0) { intdelay = (int)(1000000.0f / float(previewFrameRate)); void *base = heap->base();//base是mPreviewHeap的起始位置 //下面這個frame代表buffer在mPreviewHeap中的起始位置,還記得圖8-31嗎? //四塊MemoryBase的起始位置由下面這個代碼計算得來 uint8_t *frame = ((uint8_t *)base) + offset; //取出一幀數據,放到對應的MemoryBase中 fakeCamera->getNextFrameAsYuv422(frame); //①把含有幀數據的buffer傳遞到上層 if(mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME) mDataCb(CAMERA_MSG_PREVIEW_FRAME, buffer, mCallbackCookie); //mCurrentPreviewFrame 遞增,在0到3之間循環 mCurrentPreviewFrame = (mCurrentPreviewFrame + 1) % kBufferCount; usleep(delay);//模擬真實硬件的延時 } returnNO_ERROR; } ~~~ 讀者是否明白Camera preview的工作原理了?就是從四塊內存中取一塊出來接收數據,然后再把這塊內存傳遞到上層去處理。從緩沖使用的角度來看,mBuffers數組構成了一個成員個數為四的緩沖隊列。preview通過mData這個回調函數,把數據傳遞到上層,而CameraService實現了mData這個回調函數,這個回調函數最終會調用handlePreviewData,直接看handlePreviewData即可,代碼如下所示: **CameraService.cpp** ~~~ voidCameraService::Client::handlePreviewData(const sp<IMemory>& mem) { ssize_t offset; size_t size; //注意傳入的mem參數,它實際上是Camera HAL創建的mBuffers數組中的一個 //offset返回的是這個數組在mPreviewHeap中的偏移量 sp<IMemoryHeap> heap = mem->getMemory(&offset, &size); if (!mUseOverlay) { Mutex::Autolock surfaceLock(mSurfaceLock); if(mSurface != NULL) { //調用ISurface的postBuffer,注意我們傳入的參數是offset。 mSurface->postBuffer(offset); } } ...... } ~~~ 上面的代碼是什么意思?我們到底給ISurface傳什么了?答案很明顯: - handlePreviewData就是傳遞了一個偏移量,這個偏移量是mBuffers數組成員的首地址。可用圖8-33來表示: :-: ![](http://img.blog.csdn.net/20150802163453733?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-33 handlePreviewData示意圖 有了圖8-33,讀者明白數據傳遞的工作原理了嗎? 下面看SurfaceLayerBuffer的postBuffer函數,不過它只是一個小小的代理,真正的工作由外部類LayerBuffer完成,直接看它好了,代碼如下所示: **LayerBuffer.cpp** ~~~ void LayerBuffer::postBuffer(ssize_t offset) { sp<Source> source(getSource());//getSource返回mSource,為BufferSource類型 if(source != 0) source->postBuffer(offset);//調用BufferSource的postBuffer函數。 } ~~~ **LayerBuffer.cpp** ~~~ voidLayerBuffer::BufferSource::postBuffer(ssize_t offset) { ISurface::BufferHeap buffers; { Mutex::Autolock _l(mBufferSourceLock); buffers = mBufferHeap;//還記得圖8-32嗎? if(buffers.heap != 0) { //BufferHeap的heap變量指向MemoryHeap,下面取出它的大小 const size_t memorySize = buffers.heap->getSize(); //做一下檢查,判斷這個offset是不是有問題 if ((size_t(offset) + mBufferSize) > memorySize) { LOGE("LayerBuffer::BufferSource::postBuffer() " "invalid buffer(offset=%d, size=%d, heap-size=%d", int(offset),int(mBufferSize), int(memorySize)); return; } } } sp<Buffer> buffer; if (buffers.heap != 0) { //創建一個LayerBuffer::Buffer buffer = new LayerBuffer::Buffer(buffers, offset, mBufferSize); if(buffer->getStatus() != NO_ERROR) buffer.clear(); setBuffer(buffer);//setBuffer?我們要看看 //mLayer就是外部類LayerBuffer,調用它的invalidate函數將觸發SF的重繪 mLayer.invalidate(); } } void LayerBuffer::BufferSource::setBuffer( const sp<LayerBuffer::Buffer>& buffer) { //setBuffer函數就是簡單地將new出來的Buffer設置給成員變量mBuffer,這么做會有問題嗎?Mutex::Autolock_l(mBufferSourceLock); mBuffer = buffer; //將新的buffer設置為mBuffer,mBuffer原來指向的那個被delete } ~~~ 從數據生產者角度看,postBuffer函數將不斷地new一個Buffer出來,然后將它賦值給成員變量mBuffer,也就是說,mBuffer會不斷變化。現在從緩沖的角度來思考一下這種情況的結果: - 數據生產者有一個含四個成員的緩沖隊列,也就是mBuffers數組。 - 而數據消費者只有一個mBuffer。 這種情況會有什么后果呢?請記住這個問題,我們到最后再來揭示。下面先看mBuffer的類型Buffer是什么。 (2)數據使用的分析 Buffer被定義成LayerBuffer的內部類,代碼如下所示: **LayerBuffer.cpp** ~~~ LayerBuffer::Buffer::Buffer(constISurface::BufferHeap& buffers, ssize_t offset, size_t bufferSize) :mBufferHeap(buffers), mSupportsCopybit(false) { //注意,這個src被定義為引用,所以修改src的信息相當于修改mNativeBuffer的信息 NativeBuffer& src(mNativeBuffer); src.crop.l = 0; src.crop.t = 0; src.crop.r = buffers.w; src.crop.b = buffers.h; src.img.w =buffers.hor_stride ?: buffers.w; src.img.h =buffers.ver_stride ?: buffers.h; src.img.format = buffers.format; //這個base將指向對應的內存起始地址 src.img.base =(void*)(intptr_t(buffers.heap->base()) + offset); src.img.handle = 0; gralloc_module_tconst * module = LayerBuffer::getGrallocModule(); //做一些處理,有興趣的讀者可以去看看。 if(module && module->perform) { int err = module->perform(module, GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER, buffers.heap->heapID(), bufferSize, offset, buffers.heap->base(), &src.img.handle); mSupportsCopybit = (err == NO_ERROR); } } ~~~ 上面是Buffer的定義,其中最重要的就是這個mNativeBuffer了,它實際上保存了mBuffers數組成員的首地址。 下面看繪圖函數,也就是LayerBuffer的onDraw函數,這個函數由SF的工作線程調用,代碼如下所示: **LayerBuffer.cpp** ~~~ void LayerBuffer::onDraw(const Region& clip)const { sp<Source> source(getSource()); if(LIKELY(source != 0)) { source->onDraw(clip);//source實際類型是BufferSource,我們去看看。 } else{ clearWithOpenGL(clip); } } void LayerBuffer::BufferSource::onDraw(constRegion& clip) const { sp<Buffer> ourBuffer(getBuffer()); ......//使用這個Buffer,注意使用的時候沒有鎖控制 mLayer.drawWithOpenGL(clip, mTexture);//生成一個貼圖,然后繪制它 } ~~~ 其中getBuffer函數返回mBuffer,代碼如下所示: ~~~ sp<LayerBuffer::Buffer>LayerBuffer::BufferSource::getBuffer() const { Mutex::Autolock_l(mBufferSourceLock); returnmBuffer; } ~~~ 從上面的代碼中能發現,mBuffer的使用并沒有鎖的控制,這會導致什么問題發生呢?請再次回到前面曾強調要記住的那個問題。此時生產者的隊列有四個元素,而消費者的隊列只有一個元素,它可用圖8-34來表示: :-: ![](http://img.blog.csdn.net/20150802163511080?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-34 數據傳遞的問題示意圖 從上圖可以知道: - 使用者使用mBuffer,這是在SF的工作線程中做到的。假設mBuffer實際指向的內存為mBuffers[0]。 - 數據生產者循環更新mBuffers數組各個成員的數據內容,這是在另外一個線程中完成的。由于這兩個線程之間沒有鎖同步,這就造成了當使用者還在使用mBuffers[0]時,生產者又更新了mBuffers[0]。這會在屏幕上產生混雜的圖像。 經過實際測試得知,如果給數據使用端加上一定延時,屏幕就會出現不連續的畫面,即前一幀和后一幀的數據混雜在一起輸出。 從代碼的分析來看,這種方式確實有問題。我在真實設備上測試的結果,也在一定程度上驗證了這一點。通過修改LayerBuffer來解決這問題的難度比較大,是否可在讀寫具體緩存時加上同步控制呢(例如使用mBuffers[0]的時候調用一下lock,用完后調用unlock)?這樣就不用修改LayerBuffer了。讀者可再深入研究這個問題。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看