1/* ------------------------------------------------------------------
2 * Copyright (C) 2008 PacketVideo
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 "VideoMIO"
21#include <utils/Log.h>
22#include <surfaceflinger/ISurface.h>
23
24#include "android_surface_output.h"
25#include <media/PVPlayer.h>
26
27#include "pvlogger.h"
28#include "pv_mime_string_utils.h"
29#include "oscl_snprintf.h"
30
31#include "oscl_dll.h"
32
33// Define entry point for this DLL
34OSCL_DLL_ENTRY_POINT_DEFAULT()
35
36//The factory functions.
37#include "oscl_mem.h"
38
39using namespace android;
40
41OSCL_EXPORT_REF AndroidSurfaceOutput::AndroidSurfaceOutput() :
42    OsclTimerObject(OsclActiveObject::EPriorityNominal, "androidsurfaceoutput")
43{
44    initData();
45
46    iColorConverter = NULL;
47    mInitialized = false;
48    mPvPlayer = NULL;
49    mEmulation = false;
50    iEosReceived = false;
51    mNumberOfFramesToHold = 1;
52}
53
54status_t AndroidSurfaceOutput::set(PVPlayer* pvPlayer, const sp<ISurface>& surface, bool emulation)
55{
56    mPvPlayer = pvPlayer;
57    mEmulation = emulation;
58    setVideoSurface(surface);
59    return NO_ERROR;
60}
61
62status_t AndroidSurfaceOutput::setVideoSurface(const sp<ISurface>& surface)
63{
64    LOGV("setVideoSurface(%p)", surface.get());
65    // unregister buffers for the old surface
66    if (mSurface != NULL) {
67        LOGV("unregisterBuffers from old surface");
68        mSurface->unregisterBuffers();
69    }
70    mSurface = surface;
71    // register buffers for the new surface
72    if ((mSurface != NULL) && (mBufferHeap.heap != NULL)) {
73        LOGV("registerBuffers from old surface");
74        mSurface->registerBuffers(mBufferHeap);
75    }
76    return NO_ERROR;
77}
78
79void AndroidSurfaceOutput::initData()
80{
81    iVideoHeight = iVideoWidth = iVideoDisplayHeight = iVideoDisplayWidth = 0;
82    iVideoFormat=PVMF_MIME_FORMAT_UNKNOWN;
83    resetVideoParameterFlags();
84
85    iCommandCounter=0;
86    iLogger=NULL;
87    iCommandResponseQueue.reserve(5);
88    iWriteResponseQueue.reserve(5);
89    iObserver=NULL;
90    iLogger=NULL;
91    iPeer=NULL;
92    iState=STATE_IDLE;
93    iIsMIOConfigured = false;
94}
95
96void AndroidSurfaceOutput::ResetData()
97    //reset all data from this session.
98{
99    Cleanup();
100
101    //reset all the received media parameters.
102    iVideoFormatString="";
103    iVideoFormat=PVMF_MIME_FORMAT_UNKNOWN;
104    resetVideoParameterFlags();
105    iIsMIOConfigured = false;
106}
107
108void AndroidSurfaceOutput::resetVideoParameterFlags()
109{
110    iVideoParameterFlags = VIDEO_PARAMETERS_INVALID;
111}
112
113bool AndroidSurfaceOutput::checkVideoParameterFlags()
114{
115    return (iVideoParameterFlags & VIDEO_PARAMETERS_MASK) == VIDEO_PARAMETERS_VALID;
116}
117
118/*
119 * process the write response queue by sending writeComplete to the peer
120 * (nominally the decoder node).
121 *
122 * numFramesToHold is the number of frames to be held in the MIO. During
123 * playback, we hold the last frame which is used by SurfaceFlinger
124 * to composite the final output.
125 */
126void AndroidSurfaceOutput::processWriteResponseQueue(int numFramesToHold)
127{
128    LOGV("processWriteResponseQueue: queued = %d, numFramesToHold = %d",
129            iWriteResponseQueue.size(), numFramesToHold);
130    while (iWriteResponseQueue.size() > numFramesToHold) {
131        if (iPeer) {
132            iPeer->writeComplete(iWriteResponseQueue[0].iStatus,
133                    iWriteResponseQueue[0].iCmdId,
134                    (OsclAny*)iWriteResponseQueue[0].iContext);
135        }
136        iWriteResponseQueue.erase(&iWriteResponseQueue[0]);
137    }
138}
139
140void AndroidSurfaceOutput::Cleanup()
141//cleanup all allocated memory and release resources.
142{
143    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::Cleanup() In"));
144    while (!iCommandResponseQueue.empty())
145    {
146        if (iObserver)
147            iObserver->RequestCompleted(PVMFCmdResp(iCommandResponseQueue[0].iCmdId, iCommandResponseQueue[0].iContext, iCommandResponseQueue[0].iStatus));
148        iCommandResponseQueue.erase(&iCommandResponseQueue[0]);
149    }
150
151    processWriteResponseQueue(0);
152
153    // We'll close frame buf and delete here for now.
154    closeFrameBuf();
155
156    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::Cleanup() Out"));
157 }
158
159OSCL_EXPORT_REF AndroidSurfaceOutput::~AndroidSurfaceOutput()
160{
161    Cleanup();
162}
163
164
165PVMFStatus AndroidSurfaceOutput::connect(PvmiMIOSession& aSession, PvmiMIOObserver* aObserver)
166{
167    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::connect() called"));
168    // Each Session could have its own set of Configuration parameters
169    //in an array of structures and the session ID could be an index to that array.
170
171    //currently supports only one session
172    if (iObserver)
173        return PVMFFailure;
174
175    iObserver=aObserver;
176    return PVMFSuccess;
177}
178
179
180PVMFStatus AndroidSurfaceOutput::disconnect(PvmiMIOSession aSession)
181{
182    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::disconnect() called"));
183    //currently supports only one session
184    iObserver=NULL;
185    return PVMFSuccess;
186}
187
188
189PvmiMediaTransfer* AndroidSurfaceOutput::createMediaTransfer(PvmiMIOSession& aSession,
190                                                        PvmiKvp* read_formats, int32 read_flags,
191                                                        PvmiKvp* write_formats, int32 write_flags)
192{
193    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::createMediaTransfer() called"));
194    return (PvmiMediaTransfer*)this;
195}
196
197void AndroidSurfaceOutput::QueueCommandResponse(CommandResponse& aResp)
198{
199    //queue a command response and schedule processing.
200
201    iCommandResponseQueue.push_back(aResp);
202
203    //cancel any timer delay so the command response will happen ASAP.
204    if (IsBusy())
205        Cancel();
206
207    RunIfNotReady();
208}
209
210PVMFCommandId AndroidSurfaceOutput::QueryUUID(const PvmfMimeString& aMimeType,
211                                        Oscl_Vector<PVUuid, OsclMemAllocator>& aUuids,
212                                        bool aExactUuidsOnly, const OsclAny* aContext)
213{
214    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::QueryUUID() called"));
215
216    OSCL_UNUSED_ARG(aMimeType);
217    OSCL_UNUSED_ARG(aExactUuidsOnly);
218
219    PVMFCommandId cmdid=iCommandCounter++;
220
221    PVMFStatus status=PVMFFailure;
222    int32 err ;
223    OSCL_TRY(err, aUuids.push_back(PVMI_CAPABILITY_AND_CONFIG_PVUUID););
224    if (err==OsclErrNone)
225        status= PVMFSuccess;
226
227    CommandResponse resp(status,cmdid,aContext);
228    QueueCommandResponse(resp);
229    return cmdid;
230}
231
232
233PVMFCommandId AndroidSurfaceOutput::QueryInterface(const PVUuid& aUuid, PVInterface*& aInterfacePtr, const OsclAny* aContext)
234{
235    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::QueryInterface() called"));
236
237    PVMFCommandId cmdid=iCommandCounter++;
238
239    PVMFStatus status=PVMFFailure;
240    if(aUuid == PVMI_CAPABILITY_AND_CONFIG_PVUUID)
241    {
242        PvmiCapabilityAndConfig* myInterface = OSCL_STATIC_CAST(PvmiCapabilityAndConfig*,this);
243        aInterfacePtr = OSCL_STATIC_CAST(PVInterface*, myInterface);
244        status= PVMFSuccess;
245    }
246    else
247    {
248        status=PVMFFailure;
249    }
250
251    CommandResponse resp(status,cmdid,aContext);
252    QueueCommandResponse(resp);
253    return cmdid;
254}
255
256
257void AndroidSurfaceOutput::deleteMediaTransfer(PvmiMIOSession& aSession, PvmiMediaTransfer* media_transfer)
258{
259    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::deleteMediaTransfer() called"));
260    // This class is implementing the media transfer, so no cleanup is needed
261}
262
263
264PVMFCommandId AndroidSurfaceOutput:: Init(const OsclAny* aContext)
265{
266    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::Init() called"));
267
268    PVMFCommandId cmdid=iCommandCounter++;
269
270    PVMFStatus status=PVMFFailure;
271
272    switch(iState)
273    {
274    case STATE_LOGGED_ON:
275        status=PVMFSuccess;
276        iState=STATE_INITIALIZED;
277        break;
278
279    default:
280        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::Invalid State"));
281        status=PVMFErrInvalidState;
282        break;
283    }
284
285    CommandResponse resp(status,cmdid,aContext);
286    QueueCommandResponse(resp);
287    return cmdid;
288}
289
290PVMFCommandId AndroidSurfaceOutput::Reset(const OsclAny* aContext)
291{
292    ResetData();
293    PVMFCommandId cmdid=iCommandCounter++;
294    CommandResponse resp(PVMFSuccess,cmdid,aContext);
295    QueueCommandResponse(resp);
296    return cmdid;
297}
298
299
300PVMFCommandId AndroidSurfaceOutput::Start(const OsclAny* aContext)
301{
302    iEosReceived = false;
303    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::Start() called"));
304
305    PVMFCommandId cmdid=iCommandCounter++;
306
307    PVMFStatus status=PVMFFailure;
308
309    switch(iState)
310    {
311    case STATE_INITIALIZED:
312    case STATE_PAUSED:
313
314        iState=STATE_STARTED;
315        processWriteResponseQueue(0);
316        status=PVMFSuccess;
317        break;
318
319    default:
320        status=PVMFErrInvalidState;
321        break;
322    }
323
324    CommandResponse resp(status,cmdid,aContext);
325    QueueCommandResponse(resp);
326    return cmdid;
327}
328
329// post the last video frame to refresh screen after pause
330void AndroidSurfaceOutput::postLastFrame()
331{
332    // ignore if no surface or heap
333    if ((mSurface == NULL) || (mBufferHeap.heap == NULL)) return;
334    mSurface->postBuffer(mFrameBuffers[mFrameBufferIndex]);
335}
336
337PVMFCommandId AndroidSurfaceOutput::Pause(const OsclAny* aContext)
338{
339    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::Pause() called"));
340
341    PVMFCommandId cmdid=iCommandCounter++;
342
343    PVMFStatus status=PVMFFailure;
344
345    switch(iState)
346    {
347    case STATE_STARTED:
348
349        iState=STATE_PAUSED;
350        status=PVMFSuccess;
351
352        // post last buffer to prevent stale data
353        // if not configured, PVMFMIOConfigurationComplete is not sent
354        // there should not be any media data.
355    if(iIsMIOConfigured) {
356        postLastFrame();
357        }
358        break;
359
360    default:
361        status=PVMFErrInvalidState;
362        break;
363    }
364
365    CommandResponse resp(status,cmdid,aContext);
366    QueueCommandResponse(resp);
367    return cmdid;
368}
369
370
371PVMFCommandId AndroidSurfaceOutput::Flush(const OsclAny* aContext)
372{
373    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::Flush() called"));
374
375    PVMFCommandId cmdid=iCommandCounter++;
376
377    PVMFStatus status=PVMFFailure;
378
379    switch(iState)
380    {
381    case STATE_STARTED:
382
383        iState=STATE_INITIALIZED;
384        status=PVMFSuccess;
385        break;
386
387    default:
388        status=PVMFErrInvalidState;
389        break;
390    }
391
392    CommandResponse resp(status,cmdid,aContext);
393    QueueCommandResponse(resp);
394    return cmdid;
395}
396
397PVMFCommandId AndroidSurfaceOutput::DiscardData(const OsclAny* aContext)
398{
399    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::DiscardData() called"));
400
401    PVMFCommandId cmdid=iCommandCounter++;
402
403    //this component doesn't buffer data, so there's nothing
404    //needed here.
405
406    PVMFStatus status=PVMFSuccess;
407    processWriteResponseQueue(0);
408
409    CommandResponse resp(status,cmdid,aContext);
410    QueueCommandResponse(resp);
411    return cmdid;
412}
413
414PVMFCommandId AndroidSurfaceOutput::DiscardData(PVMFTimestamp aTimestamp, const OsclAny* aContext)
415{
416    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::DiscardData() called"));
417
418    PVMFCommandId cmdid=iCommandCounter++;
419
420    aTimestamp = 0;
421
422    //this component doesn't buffer data, so there's nothing
423    //needed here.
424
425    PVMFStatus status=PVMFSuccess;
426    processWriteResponseQueue(0);
427
428    CommandResponse resp(status,cmdid,aContext);
429    QueueCommandResponse(resp);
430    return cmdid;
431}
432
433PVMFCommandId AndroidSurfaceOutput::Stop(const OsclAny* aContext)
434{
435    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::Stop() called"));
436
437    PVMFCommandId cmdid=iCommandCounter++;
438
439    PVMFStatus status=PVMFFailure;
440
441    switch(iState)
442    {
443    case STATE_STARTED:
444    case STATE_PAUSED:
445
446#ifdef PERFORMANCE_MEASUREMENTS_ENABLED
447        // FIXME: This should be moved to OMAP library
448    PVOmapVideoProfile.MarkEndTime();
449    PVOmapVideoProfile.PrintStats();
450    PVOmapVideoProfile.Reset();
451#endif
452
453        iState=STATE_INITIALIZED;
454        status=PVMFSuccess;
455        break;
456
457    default:
458        status=PVMFErrInvalidState;
459        break;
460    }
461
462    CommandResponse resp(status,cmdid,aContext);
463    QueueCommandResponse(resp);
464    return cmdid;
465}
466
467PVMFCommandId AndroidSurfaceOutput::CancelAllCommands(const OsclAny* aContext)
468{
469    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::CancelAllCommands() called"));
470
471    PVMFCommandId cmdid=iCommandCounter++;
472
473    //commands are executed immediately upon being received, so
474    //it isn't really possible to cancel them.
475
476    PVMFStatus status=PVMFSuccess;
477
478    CommandResponse resp(status,cmdid,aContext);
479    QueueCommandResponse(resp);
480    return cmdid;
481}
482
483PVMFCommandId AndroidSurfaceOutput::CancelCommand(PVMFCommandId aCmdId, const OsclAny* aContext)
484{
485    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::CancelCommand() called"));
486
487    PVMFCommandId cmdid=iCommandCounter++;
488
489    //commands are executed immediately upon being received, so
490    //it isn't really possible to cancel them.
491
492    //see if the response is still queued.
493    PVMFStatus status=PVMFFailure;
494    for (uint32 i=0;i<iCommandResponseQueue.size();i++)
495    {
496        if (iCommandResponseQueue[i].iCmdId==aCmdId)
497        {
498            status=PVMFSuccess;
499            break;
500        }
501    }
502
503    CommandResponse resp(status,cmdid,aContext);
504    QueueCommandResponse(resp);
505    return cmdid;
506}
507
508void AndroidSurfaceOutput::ThreadLogon()
509{
510    if(iState==STATE_IDLE)
511    {
512        iLogger = PVLogger::GetLoggerObject("PVOmapVideo");
513        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::ThreadLogon() called"));
514        AddToScheduler();
515        iState=STATE_LOGGED_ON;
516    }
517}
518
519
520void AndroidSurfaceOutput::ThreadLogoff()
521{
522    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::ThreadLogoff() called"));
523
524    if(iState!=STATE_IDLE)
525    {
526        RemoveFromScheduler();
527        iLogger=NULL;
528        iState=STATE_IDLE;
529    }
530}
531
532
533void AndroidSurfaceOutput::setPeer(PvmiMediaTransfer* aPeer)
534{
535    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::setPeer() called"));
536    // Set the observer
537    iPeer = aPeer;
538}
539
540
541void AndroidSurfaceOutput::useMemoryAllocators(OsclMemAllocator* write_alloc)
542{
543    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::useMemoryAllocators() called"));
544    //not supported.
545}
546
547// This routine will determine whether data can be accepted in a writeAsync
548// call and if not, will return true;
549bool AndroidSurfaceOutput::CheckWriteBusy(uint32 aSeqNum)
550{
551    // for all other cases, accept data now.
552    return false;
553}
554
555PVMFCommandId AndroidSurfaceOutput::writeAsync(uint8 aFormatType, int32 aFormatIndex, uint8* aData, uint32 aDataLen,
556                                        const PvmiMediaXferHeader& data_header_info, OsclAny* aContext)
557{
558    // Do a leave if MIO is not configured except when it is an EOS
559    if (!iIsMIOConfigured
560            &&
561            !((PVMI_MEDIAXFER_FMT_TYPE_NOTIFICATION == aFormatType)
562              && (PVMI_MEDIAXFER_FMT_INDEX_END_OF_STREAM == aFormatIndex)))
563    {
564        LOGE("data is pumped in before MIO is configured");
565        OSCL_LEAVE(OsclErrInvalidState);
566        return -1;
567    }
568
569    uint32 aSeqNum=data_header_info.seq_num;
570    PVMFTimestamp aTimestamp=data_header_info.timestamp;
571    uint32 flags=data_header_info.flags;
572
573    if (aSeqNum < 6)
574    {
575        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
576            (0,"AndroidSurfaceOutput::writeAsync() seqnum %d ts %d context %d",aSeqNum,aTimestamp,aContext));
577
578        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
579            (0,"AndroidSurfaceOutput::writeAsync() Format Type %d Format Index %d length %d",aFormatType,aFormatIndex,aDataLen));
580    }
581
582    PVMFStatus status=PVMFFailure;
583
584    switch(aFormatType)
585    {
586    case PVMI_MEDIAXFER_FMT_TYPE_COMMAND :
587        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
588            (0,"AndroidSurfaceOutput::writeAsync() called with Command info."));
589        //ignore
590        status= PVMFSuccess;
591        break;
592
593    case PVMI_MEDIAXFER_FMT_TYPE_NOTIFICATION :
594        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
595            (0,"AndroidSurfaceOutput::writeAsync() called with Notification info."));
596        switch(aFormatIndex)
597        {
598        case PVMI_MEDIAXFER_FMT_INDEX_END_OF_STREAM:
599            iEosReceived = true;
600            break;
601        default:
602            break;
603        }
604        //ignore
605        status= PVMFSuccess;
606        break;
607
608    case PVMI_MEDIAXFER_FMT_TYPE_DATA :
609        switch(aFormatIndex)
610        {
611        case PVMI_MEDIAXFER_FMT_INDEX_FMT_SPECIFIC_INFO:
612            //format-specific info contains codec headers.
613            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
614                (0,"AndroidSurfaceOutput::writeAsync() called with format-specific info."));
615
616            if (iState<STATE_INITIALIZED)
617            {
618                PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
619                    (0,"AndroidSurfaceOutput::writeAsync: Error - Invalid state"));
620                status=PVMFErrInvalidState;
621            }
622            else
623            {
624                status= PVMFSuccess;
625            }
626
627            break;
628
629        case PVMI_MEDIAXFER_FMT_INDEX_DATA:
630            //data contains the media bitstream.
631
632            //Verify the state
633            if (iState!=STATE_STARTED)
634            {
635                PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
636                    (0,"AndroidSurfaceOutput::writeAsync: Error - Invalid state"));
637                status=PVMFErrInvalidState;
638            }
639            else
640            {
641
642                //printf("V WriteAsync { seq=%d, ts=%d }\n", data_header_info.seq_num, data_header_info.timestamp);
643
644                // Call playback to send data to IVA for Color Convert
645                status = writeFrameBuf(aData, aDataLen, data_header_info);
646
647                PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
648                   (0,"AndroidSurfaceOutput::writeAsync: Playback Progress - frame %d",iFrameNumber++));
649            }
650            break;
651
652        default:
653            PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
654                (0,"AndroidSurfaceOutput::writeAsync: Error - unrecognized format index"));
655            status= PVMFFailure;
656            break;
657        }
658        break;
659
660    default:
661        PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
662            (0,"AndroidSurfaceOutput::writeAsync: Error - unrecognized format type"));
663        status= PVMFFailure;
664        break;
665    }
666
667    //Schedule asynchronous response
668    PVMFCommandId cmdid=iCommandCounter++;
669    WriteResponse resp(status,cmdid,aContext,aTimestamp);
670    iWriteResponseQueue.push_back(resp);
671    RunIfNotReady();
672
673    return cmdid;
674}
675
676void AndroidSurfaceOutput::writeComplete(PVMFStatus aStatus, PVMFCommandId  write_cmd_id, OsclAny* aContext)
677{
678    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::writeComplete() called"));
679    //won't be called since this component is a sink.
680}
681
682
683PVMFCommandId  AndroidSurfaceOutput::readAsync(uint8* data, uint32 max_data_len, OsclAny* aContext,
684                                            int32* formats, uint16 num_formats)
685{
686    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::readAsync() called"));
687    //read not supported.
688    OsclError::Leave(OsclErrNotSupported);
689    return -1;
690}
691
692
693void AndroidSurfaceOutput::readComplete(PVMFStatus aStatus, PVMFCommandId  read_cmd_id, int32 format_index,
694                                    const PvmiMediaXferHeader& data_header_info, OsclAny* aContext)
695{
696    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::readComplete() called"));
697    //won't be called since this component is a sink.
698}
699
700
701void AndroidSurfaceOutput::statusUpdate(uint32 status_flags)
702{
703    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::statusUpdate() called"));
704    //won't be called since this component is a sink.
705}
706
707
708void AndroidSurfaceOutput::cancelCommand(PVMFCommandId  command_id)
709{
710    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::cancelCommand() called"));
711
712    //the purpose of this API is to cancel a writeAsync command and report
713    //completion ASAP.
714
715    //in this implementation, the write commands are executed immediately
716    //when received so it isn't really possible to cancel.
717    //just report completion immediately.
718    processWriteResponseQueue(0);
719}
720
721void AndroidSurfaceOutput::cancelAllCommands()
722{
723    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::cancelAllCommands() called"));
724
725    //the purpose of this API is to cancel all writeAsync commands and report
726    //completion ASAP.
727
728    //in this implementaiton, the write commands are executed immediately
729    //when received so it isn't really possible to cancel.
730    //just report completion immediately.
731
732    for (uint32 i=0;i<iWriteResponseQueue.size();i++)
733    {
734        //report completion
735        if (iPeer)
736            iPeer->writeComplete(iWriteResponseQueue[i].iStatus,iWriteResponseQueue[i].iCmdId,(OsclAny*)iWriteResponseQueue[i].iContext);
737        iWriteResponseQueue.erase(&iWriteResponseQueue[i]);
738    }
739}
740
741void AndroidSurfaceOutput::setObserver (PvmiConfigAndCapabilityCmdObserver* aObserver)
742{
743    OSCL_UNUSED_ARG(aObserver);
744    //not needed since this component only supports synchronous capability & config
745    //APIs.
746}
747
748PVMFStatus AndroidSurfaceOutput::getParametersSync(PvmiMIOSession aSession, PvmiKeyType aIdentifier,
749                                              PvmiKvp*& aParameters, int& num_parameter_elements,
750                                              PvmiCapabilityContext aContext)
751{
752    OSCL_UNUSED_ARG(aSession);
753    OSCL_UNUSED_ARG(aContext);
754    aParameters=NULL;
755
756    // This is a query for the list of supported formats.
757    if(pv_mime_strcmp(aIdentifier, INPUT_FORMATS_CAP_QUERY) == 0)
758    {
759        aParameters=(PvmiKvp*)oscl_malloc(sizeof(PvmiKvp));
760        if (aParameters == NULL) return PVMFErrNoMemory;
761        aParameters[num_parameter_elements++].value.pChar_value=(char*) PVMF_MIME_YUV420;
762
763        return PVMFSuccess;
764    }
765
766    //unrecognized key.
767    return PVMFFailure;
768}
769
770PVMFStatus AndroidSurfaceOutput::releaseParameters(PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements)
771{
772    //release parameters that were allocated by this component.
773    if (aParameters)
774    {
775        oscl_free(aParameters);
776        return PVMFSuccess;
777    }
778    return PVMFFailure;
779}
780
781void AndroidSurfaceOutput ::createContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext)
782{
783    OsclError::Leave(OsclErrNotSupported);
784}
785
786void AndroidSurfaceOutput::setContextParameters(PvmiMIOSession aSession, PvmiCapabilityContext& aContext,
787                                           PvmiKvp* aParameters, int num_parameter_elements)
788{
789    OsclError::Leave(OsclErrNotSupported);
790}
791
792void AndroidSurfaceOutput::DeleteContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext)
793{
794    OsclError::Leave(OsclErrNotSupported);
795}
796
797
798void AndroidSurfaceOutput::setParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters,
799                                        int num_elements, PvmiKvp * & aRet_kvp)
800{
801    OSCL_UNUSED_ARG(aSession);
802
803    aRet_kvp = NULL;
804
805    LOGV("setParametersSync");
806    for (int32 i=0;i<num_elements;i++)
807    {
808        //Check against known video parameter keys...
809        if (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_FORMAT_KEY) == 0)
810        {
811            iVideoFormatString=aParameters[i].value.pChar_value;
812            iVideoFormat=iVideoFormatString.get_str();
813            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
814                (0,"AndroidSurfaceOutput::setParametersSync() Video Format Key, Value %s",iVideoFormatString.get_str()));
815        }
816        else if (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_WIDTH_KEY) == 0)
817        {
818            iVideoWidth=(int32)aParameters[i].value.uint32_value;
819            iVideoParameterFlags |= VIDEO_WIDTH_VALID;
820            LOGV("iVideoWidth=%d", iVideoWidth);
821            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
822                (0,"AndroidSurfaceOutput::setParametersSync() Video Width Key, Value %d",iVideoWidth));
823        }
824        else if (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_HEIGHT_KEY) == 0)
825        {
826            iVideoHeight=(int32)aParameters[i].value.uint32_value;
827            iVideoParameterFlags |= VIDEO_HEIGHT_VALID;
828            LOGV("iVideoHeight=%d", iVideoHeight);
829            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
830                (0,"AndroidSurfaceOutput::setParametersSync() Video Height Key, Value %d",iVideoHeight));
831        }
832        else if (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_DISPLAY_HEIGHT_KEY) == 0)
833        {
834            iVideoDisplayHeight=(int32)aParameters[i].value.uint32_value;
835            iVideoParameterFlags |= DISPLAY_HEIGHT_VALID;
836            LOGV("iVideoDisplayHeight=%d", iVideoDisplayHeight);
837            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
838                (0,"AndroidSurfaceOutput::setParametersSync() Video Display Height Key, Value %d",iVideoDisplayHeight));
839        }
840        else if (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_DISPLAY_WIDTH_KEY) == 0)
841        {
842            iVideoDisplayWidth=(int32)aParameters[i].value.uint32_value;
843            iVideoParameterFlags |= DISPLAY_WIDTH_VALID;
844            LOGV("iVideoDisplayWidth=%d", iVideoDisplayWidth);
845            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
846                (0,"AndroidSurfaceOutput::setParametersSync() Video Display Width Key, Value %d",iVideoDisplayWidth));
847        }
848        else if (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_SUBFORMAT_KEY) == 0)
849        {
850            iVideoSubFormat=aParameters[i].value.pChar_value;
851            iVideoParameterFlags |= VIDEO_SUBFORMAT_VALID;
852            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
853                    (0,"AndroidSurfaceOutput::setParametersSync() Video SubFormat Key, Value %s",iVideoSubFormat.getMIMEStrPtr()));
854
855LOGV("VIDEO SUBFORMAT SET TO %s\n",iVideoSubFormat.getMIMEStrPtr());
856        }
857        else
858        {
859            //if we get here the key is unrecognized.
860
861            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
862                (0,"AndroidSurfaceOutput::setParametersSync() Error, unrecognized key = %s", aParameters[i].key));
863
864            //set the return value to indicate the unrecognized key
865            //and return.
866            aRet_kvp = &aParameters[i];
867            return;
868        }
869    }
870    uint32 mycache = iVideoParameterFlags ;
871    // if initialization is complete, update the app display info
872    if( checkVideoParameterFlags() )
873    initCheck();
874    iVideoParameterFlags = mycache;
875
876    // when all necessary parameters are received, send
877    // PVMFMIOConfigurationComplete event to observer
878    if(!iIsMIOConfigured && checkVideoParameterFlags() )
879    {
880        iIsMIOConfigured = true;
881        if(iObserver)
882        {
883            iObserver->ReportInfoEvent(PVMFMIOConfigurationComplete);
884        }
885    }
886}
887
888PVMFCommandId AndroidSurfaceOutput::setParametersAsync(PvmiMIOSession aSession, PvmiKvp* aParameters,
889                                                  int num_elements, PvmiKvp*& aRet_kvp, OsclAny* context)
890{
891    OsclError::Leave(OsclErrNotSupported);
892    return -1;
893}
894
895uint32 AndroidSurfaceOutput::getCapabilityMetric (PvmiMIOSession aSession)
896{
897    return 0;
898}
899
900PVMFStatus AndroidSurfaceOutput::verifyParametersSync (PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements)
901{
902    OSCL_UNUSED_ARG(aSession);
903
904    // Go through each parameter
905    for (int32 i=0; i<num_elements; i++) {
906        char* compstr = NULL;
907        pv_mime_string_extract_type(0, aParameters[i].key, compstr);
908        if (pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf/media/format-type")) == 0) {
909            if (pv_mime_strcmp(aParameters[i].value.pChar_value, PVMF_MIME_YUV420) == 0) {
910                return PVMFSuccess;
911            }
912            else {
913                return PVMFErrNotSupported;
914            }
915        }
916    }
917    return PVMFSuccess;
918}
919
920//
921// Private section
922//
923
924void AndroidSurfaceOutput::Run()
925{
926    //send async command responses
927    while (!iCommandResponseQueue.empty())
928    {
929        if (iObserver)
930            iObserver->RequestCompleted(PVMFCmdResp(iCommandResponseQueue[0].iCmdId, iCommandResponseQueue[0].iContext, iCommandResponseQueue[0].iStatus));
931        iCommandResponseQueue.erase(&iCommandResponseQueue[0]);
932    }
933
934    //send async write completion
935    if (iEosReceived) {
936        LOGV("Flushing buffers after EOS");
937        processWriteResponseQueue(0);
938    } else {
939        processWriteResponseQueue(mNumberOfFramesToHold);
940    }
941}
942
943// create a frame buffer for software codecs
944OSCL_EXPORT_REF bool AndroidSurfaceOutput::initCheck()
945{
946
947    // initialize only when we have all the required parameters
948    if (!checkVideoParameterFlags())
949        return mInitialized;
950
951    // release resources if previously initialized
952    closeFrameBuf();
953
954    // reset flags in case display format changes in the middle of a stream
955    resetVideoParameterFlags();
956
957    // copy parameters in case we need to adjust them
958    int displayWidth = iVideoDisplayWidth;
959    int displayHeight = iVideoDisplayHeight;
960    int frameWidth = iVideoWidth;
961    int frameHeight = iVideoHeight;
962    int frameSize;
963
964    // RGB-565 frames are 2 bytes/pixel
965    displayWidth = (displayWidth + 1) & -2;
966    displayHeight = (displayHeight + 1) & -2;
967    frameWidth = (frameWidth + 1) & -2;
968    frameHeight = (frameHeight + 1) & -2;
969    frameSize = frameWidth * frameHeight * 2;
970
971    // create frame buffer heap and register with surfaceflinger
972    sp<MemoryHeapBase> heap = new MemoryHeapBase(frameSize * kBufferCount);
973    if (heap->heapID() < 0) {
974        LOGE("Error creating frame buffer heap");
975        return false;
976    }
977
978    mBufferHeap = ISurface::BufferHeap(displayWidth, displayHeight,
979            frameWidth, frameHeight, PIXEL_FORMAT_RGB_565, heap);
980    mSurface->registerBuffers(mBufferHeap);
981
982    // create frame buffers
983    for (int i = 0; i < kBufferCount; i++) {
984        mFrameBuffers[i] = i * frameSize;
985    }
986
987    // initialize software color converter
988    iColorConverter = ColorConvert16::NewL();
989    iColorConverter->Init(displayWidth, displayHeight, frameWidth, displayWidth, displayHeight, displayWidth, CCROTATE_NONE);
990    iColorConverter->SetMemHeight(frameHeight);
991    iColorConverter->SetMode(1);
992
993    LOGV("video = %d x %d", displayWidth, displayHeight);
994    LOGV("frame = %d x %d", frameWidth, frameHeight);
995    LOGV("frame #bytes = %d", frameSize);
996
997    // register frame buffers with SurfaceFlinger
998    mFrameBufferIndex = 0;
999    mInitialized = true;
1000    mPvPlayer->sendEvent(MEDIA_SET_VIDEO_SIZE, iVideoDisplayWidth, iVideoDisplayHeight);
1001
1002    return mInitialized;
1003}
1004
1005OSCL_EXPORT_REF PVMFStatus AndroidSurfaceOutput::writeFrameBuf(uint8* aData, uint32 aDataLen, const PvmiMediaXferHeader& data_header_info)
1006{
1007    // post to SurfaceFlinger
1008    if ((mSurface != NULL) && (mBufferHeap.heap != NULL)) {
1009        if (++mFrameBufferIndex == kBufferCount) mFrameBufferIndex = 0;
1010        iColorConverter->Convert(aData, static_cast<uint8*>(mBufferHeap.heap->base()) + mFrameBuffers[mFrameBufferIndex]);
1011        mSurface->postBuffer(mFrameBuffers[mFrameBufferIndex]);
1012    }
1013    return PVMFSuccess;
1014}
1015
1016OSCL_EXPORT_REF void AndroidSurfaceOutput::closeFrameBuf()
1017{
1018    LOGV("closeFrameBuf");
1019    if (!mInitialized) return;
1020
1021    mInitialized = false;
1022    if (mSurface.get()) {
1023        LOGV("unregisterBuffers");
1024        mSurface->unregisterBuffers();
1025    }
1026
1027    // free frame buffers
1028    LOGV("free frame buffers");
1029    for (int i = 0; i < kBufferCount; i++) {
1030        mFrameBuffers[i] = 0;
1031    }
1032
1033    // free heaps
1034    LOGV("free frame heap");
1035    mBufferHeap.heap.clear();
1036
1037    // free color converter
1038    if (iColorConverter != 0)
1039    {
1040        LOGV("free color converter");
1041        delete iColorConverter;
1042        iColorConverter = 0;
1043    }
1044}
1045
1046OSCL_EXPORT_REF bool AndroidSurfaceOutput::GetVideoSize(int *w, int *h) {
1047
1048    *w = iVideoDisplayWidth;
1049    *h = iVideoDisplayHeight;
1050    return iVideoDisplayWidth != 0 && iVideoDisplayHeight != 0;
1051}
1052