• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ------------------------------------------------------------------
2  * Copyright (C) 2009 Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13  * express or implied.
14  * See the License for the specific language governing permissions
15  * and limitations under the License.
16  * -------------------------------------------------------------------
17  */
18 
19 //#define LOG_NDEBUG 0
20 #define LOG_TAG "VideoMio72xx"
21 #include <utils/Log.h>
22 
23 #include "android_surface_output_msm72xx.h"
24 #include <media/PVPlayer.h>
25 
26 #define PLATFORM_PRIVATE_PMEM 1
27 
28 #if HAVE_ANDROID_OS
29 #include <linux/android_pmem.h>
30 #endif
31 
32 using namespace android;
33 
34 static const char* pmem_adsp = "/dev/pmem_adsp";
35 static const char* pmem = "/dev/pmem";
36 
AndroidSurfaceOutputMsm72xx()37 OSCL_EXPORT_REF AndroidSurfaceOutputMsm72xx::AndroidSurfaceOutputMsm72xx() :
38     AndroidSurfaceOutput()
39 {
40     mHardwareCodec = false;
41 }
42 
~AndroidSurfaceOutputMsm72xx()43 OSCL_EXPORT_REF AndroidSurfaceOutputMsm72xx::~AndroidSurfaceOutputMsm72xx()
44 {
45 }
46 
47 // create a frame buffer for software codecs
initCheck()48 OSCL_EXPORT_REF bool AndroidSurfaceOutputMsm72xx::initCheck()
49 {
50 
51     // initialize only when we have all the required parameters
52     if (((iVideoParameterFlags & VIDEO_SUBFORMAT_VALID) == 0) || !checkVideoParameterFlags())
53         return mInitialized;
54 
55     // release resources if previously initialized
56     closeFrameBuf();
57 
58     // reset flags in case display format changes in the middle of a stream
59     resetVideoParameterFlags();
60 
61     // copy parameters in case we need to adjust them
62     int displayWidth = iVideoDisplayWidth;
63     int displayHeight = iVideoDisplayHeight;
64     int frameWidth = iVideoWidth;
65     int frameHeight = iVideoHeight;
66     int frameSize;
67 
68     // MSM72xx hardware codec uses semi-planar format
69     if (iVideoSubFormat == PVMF_MIME_YUV420_SEMIPLANAR_YVU) {
70         LOGV("using hardware codec");
71         mHardwareCodec = true;
72         // Workaround for tearing from SF
73         // But please make sure that the number of unique output
74         // buffers are more than 2; otherwise, the video playback
75         // will freeze due to starvation.
76         mNumberOfFramesToHold = 2;
77     } else {
78         LOGV("using software codec");
79 
80         // YUV420 frames are 1.5 bytes/pixel
81         frameSize = (frameWidth * frameHeight * 3) / 2;
82 
83         // create frame buffer heap
84         sp<MemoryHeapBase> master = new MemoryHeapBase(pmem_adsp, frameSize * kBufferCount);
85         if (master->heapID() < 0) {
86             LOGE("Error creating frame buffer heap");
87             return false;
88         }
89         master->setDevice(pmem);
90         sp<MemoryHeapPmem> heap = new MemoryHeapPmem(master, 0);
91         heap->slap();
92         mBufferHeap = ISurface::BufferHeap(displayWidth, displayHeight,
93                 frameWidth, frameHeight, HAL_PIXEL_FORMAT_YCrCb_420_SP, heap);
94         master.clear();
95         mSurface->registerBuffers(mBufferHeap);
96 
97         // create frame buffers
98         for (int i = 0; i < kBufferCount; i++) {
99             mFrameBuffers[i] = i * frameSize;
100         }
101 
102         LOGV("video = %d x %d", displayWidth, displayHeight);
103         LOGV("frame = %d x %d", frameWidth, frameHeight);
104         LOGV("frame #bytes = %d", frameSize);
105 
106         // register frame buffers with SurfaceFlinger
107         mFrameBufferIndex = 0;
108     }
109 
110     mInitialized = true;
111     LOGV("sendEvent(MEDIA_SET_VIDEO_SIZE, %d, %d)", iVideoDisplayWidth, iVideoDisplayHeight);
112     mPvPlayer->sendEvent(MEDIA_SET_VIDEO_SIZE, iVideoDisplayWidth, iVideoDisplayHeight);
113     return mInitialized;
114 }
115 
writeFrameBuf(uint8 * aData,uint32 aDataLen,const PvmiMediaXferHeader & data_header_info)116 PVMFStatus AndroidSurfaceOutputMsm72xx::writeFrameBuf(uint8* aData, uint32 aDataLen, const PvmiMediaXferHeader& data_header_info)
117 {
118     // OK to drop frames if no surface
119     if (mSurface == 0) return PVMFSuccess;
120 
121     // hardware codec
122     if (mHardwareCodec) {
123 
124         // initialize frame buffer heap
125         if (mBufferHeap.heap == 0) {
126             LOGV("initializing for hardware");
127             LOGV("private data pointer is 0%p\n", data_header_info.private_data_ptr);
128 
129             // check for correct video format
130             if (iVideoSubFormat != PVMF_MIME_YUV420_SEMIPLANAR_YVU) return PVMFFailure;
131 
132             uint32 fd;
133             if (!getPmemFd(data_header_info.private_data_ptr, &fd)) {
134                 LOGE("Error getting pmem heap from private_data_ptr");
135                 return PVMFFailure;
136             }
137 
138             // ugly hack to pass an sp<MemoryHeapBase> as an int
139             sp<MemoryHeapBase> master = (MemoryHeapBase *) fd;
140             master->setDevice(pmem);
141 
142             // create new reference
143             uint32_t heap_flags = master->getFlags() & MemoryHeapBase::NO_CACHING;
144             sp<MemoryHeapPmem> heap = new MemoryHeapPmem(master, heap_flags);
145             heap->slap();
146 
147             // register frame buffers with SurfaceFlinger
148             mBufferHeap = ISurface::BufferHeap(iVideoDisplayWidth, iVideoDisplayHeight,
149                     iVideoWidth, iVideoHeight, HAL_PIXEL_FORMAT_YCrCb_420_SP, heap);
150             master.clear();
151             mSurface->registerBuffers(mBufferHeap);
152         }
153 
154         // get pmem offset and post to SurfaceFlinger
155         if (!getOffset(data_header_info.private_data_ptr, &mOffset)) {
156             LOGE("Error getting pmem offset from private_data_ptr");
157             return PVMFFailure;
158         }
159         mSurface->postBuffer(mOffset);
160     } else {
161         // software codec
162         if (++mFrameBufferIndex == kBufferCount) mFrameBufferIndex = 0;
163         convertFrame(aData, static_cast<uint8*>(mBufferHeap.heap->base()) + mFrameBuffers[mFrameBufferIndex], aDataLen);
164         // post to SurfaceFlinger
165         mSurface->postBuffer(mFrameBuffers[mFrameBufferIndex]);
166     }
167 
168     return PVMFSuccess;
169 }
170 
171 // post the last video frame to refresh screen after pause
postLastFrame()172 void AndroidSurfaceOutputMsm72xx::postLastFrame()
173 {
174     // ignore if no surface or heap
175     if ((mSurface == NULL) || (mBufferHeap.heap == NULL)) return;
176 
177     if (mHardwareCodec) {
178         mSurface->postBuffer(mOffset);
179     } else {
180         mSurface->postBuffer(mFrameBuffers[mFrameBufferIndex]);
181     }
182 }
183 
getPmemFd(OsclAny * private_data_ptr,uint32 * pmemFD)184 bool AndroidSurfaceOutputMsm72xx::getPmemFd(OsclAny *private_data_ptr, uint32 *pmemFD)
185 {
186     PLATFORM_PRIVATE_LIST *listPtr = NULL;
187     PLATFORM_PRIVATE_PMEM_INFO *pmemInfoPtr = NULL;
188     bool returnType = false;
189     LOGV("in getPmemfd - privatedataptr=%p\n",private_data_ptr);
190     listPtr = (PLATFORM_PRIVATE_LIST*) private_data_ptr;
191 
192     for (uint32 i=0;i<listPtr->nEntries;i++)
193     {
194         if(listPtr->entryList->type == PLATFORM_PRIVATE_PMEM)
195         {
196             LOGV("in getPmemfd - entry type = %d\n",listPtr->entryList->type);
197           pmemInfoPtr = (PLATFORM_PRIVATE_PMEM_INFO*) (listPtr->entryList->entry);
198           returnType = true;
199           if(pmemInfoPtr){
200             *pmemFD = pmemInfoPtr->pmem_fd;
201             LOGV("in getPmemfd - pmemFD = %d\n",*pmemFD);
202           }
203           break;
204         }
205     }
206     return returnType;
207 }
208 
getOffset(OsclAny * private_data_ptr,uint32 * offset)209 bool AndroidSurfaceOutputMsm72xx::getOffset(OsclAny *private_data_ptr, uint32 *offset)
210 {
211     PLATFORM_PRIVATE_LIST *listPtr = NULL;
212     PLATFORM_PRIVATE_PMEM_INFO *pmemInfoPtr = NULL;
213     bool returnType = false;
214 
215     listPtr = (PLATFORM_PRIVATE_LIST*) private_data_ptr;
216     LOGV("in getOffset: listPtr = %p\n",listPtr);
217     for (uint32 i=0;i<listPtr->nEntries;i++)
218     {
219         if(listPtr->entryList->type == PLATFORM_PRIVATE_PMEM)
220         {
221             LOGV(" in getOffset: entrytype = %d\n",listPtr->entryList->type);
222 
223           pmemInfoPtr = (PLATFORM_PRIVATE_PMEM_INFO*) (listPtr->entryList->entry);
224           returnType = true;
225           if(pmemInfoPtr){
226             *offset = pmemInfoPtr->offset;
227             LOGV("in getOffset: offset = %d\n",*offset);
228           }
229           break;
230         }
231     }
232     return returnType;
233 }
234 
byteOffset(void * p,size_t offset)235 static inline void* byteOffset(void* p, size_t offset) { return (void*)((uint8_t*)p + offset); }
236 
convertFrame(void * src,void * dst,size_t len)237 void AndroidSurfaceOutputMsm72xx::convertFrame(void* src, void* dst, size_t len)
238 {
239     // copy the Y plane
240     size_t y_plane_size = iVideoWidth * iVideoHeight;
241     //LOGV("len=%u, y_plane_size=%u", len, y_plane_size);
242     memcpy(dst, src, y_plane_size + iVideoWidth);
243 
244     // re-arrange U's and V's
245     uint16_t* pu = (uint16_t*)byteOffset(src, y_plane_size);
246     uint16_t* pv = (uint16_t*)byteOffset(pu, y_plane_size / 4);
247     uint32_t* p = (uint32_t*)byteOffset(dst, y_plane_size);
248 
249     int count = y_plane_size / 8;
250     //LOGV("u = %p, v = %p, p = %p, count = %d", pu, pv, p, count);
251     do {
252         uint32_t u = *pu++;
253         uint32_t v = *pv++;
254         *p++ = ((u & 0xff) << 8) | ((u & 0xff00) << 16) | (v & 0xff) | ((v & 0xff00) << 8);
255     } while (--count);
256 }
257 
258 // factory function for playerdriver linkage
createVideoMio()259 extern "C" AndroidSurfaceOutputMsm72xx* createVideoMio()
260 {
261     return new AndroidSurfaceOutputMsm72xx();
262 }
263 
264