VideoEditorVideoEncoder.cpp revision e946f0bfe7f5c63d4b10497ccc87ddb5b002b51d
1/*
2 * Copyright (C) 2011 The 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 express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16/**
17*************************************************************************
18* @file   VideoEditorVideoEncoder.cpp
19* @brief  StageFright shell video encoder
20*************************************************************************
21*/
22#define LOG_NDEBUG 1
23#define LOG_TAG "VIDEOEDITOR_VIDEOENCODER"
24
25/*******************
26 *     HEADERS     *
27 *******************/
28#include "M4OSA_Debug.h"
29#include "M4SYS_AccessUnit.h"
30#include "VideoEditorVideoEncoder.h"
31#include "VideoEditorUtils.h"
32
33#include "utils/Log.h"
34#include <media/stagefright/MediaSource.h>
35#include <media/stagefright/MediaDebug.h>
36#include <media/stagefright/MediaDefs.h>
37#include <media/stagefright/MetaData.h>
38#include <media/stagefright/OMXClient.h>
39#include <media/stagefright/OMXCodec.h>
40#include "OMX_Video.h"
41
42/********************
43 *   DEFINITIONS    *
44 ********************/
45
46// Minimum number of buffer in the source in order to allow encoding
47#define VIDEOEDITOR_MIN_BUFFER_NB 15
48
49// Not enough source buffers available
50#define M4WAR_SF_LOW_BUFFER M4OSA_ERR_CREATE(M4_WAR, 0xFF, 0x00001)
51
52// Encoder color format
53#define VIDEOEDITOR_ENCODER_COLOR_FORMAT OMX_COLOR_FormatYUV420Planar
54
55// Force using hardware encoder
56#define VIDEOEDITOR_FORCECODEC kHardwareCodecsOnly
57
58// Force Encoder to produce a DSI by sending fake input frames upon creation
59#define VIDEOEDITOR_ENCODER_GET_DSI_AT_CREATION
60
61#if defined(VIDEOEDITOR_ENCODER_GET_DSI_AT_CREATION) && \
62    !defined(VIDEOEDITOR_FORCECODEC)
63    #error "Cannot force DSI retrieval if codec type is not fixed"
64#endif
65
66/********************
67 *   SOURCE CLASS   *
68 ********************/
69
70namespace android {
71
72struct VideoEditorVideoEncoderSource : public MediaSource {
73    public:
74        static sp<VideoEditorVideoEncoderSource> Create(
75            const sp<MetaData> &format);
76        virtual status_t start(MetaData *params = NULL);
77        virtual status_t stop();
78        virtual sp<MetaData> getFormat();
79        virtual status_t read(MediaBuffer **buffer,
80            const ReadOptions *options = NULL);
81        virtual int32_t storeBuffer(MediaBuffer *buffer);
82
83    protected:
84        virtual ~VideoEditorVideoEncoderSource();
85
86    private:
87        struct MediaBufferChain {
88            MediaBuffer* buffer;
89            MediaBufferChain* nextLink;
90        };
91        enum State {
92            CREATED,
93            STARTED,
94            ERROR
95        };
96        VideoEditorVideoEncoderSource(const sp<MetaData> &format);
97
98        // Don't call me
99        VideoEditorVideoEncoderSource(const VideoEditorVideoEncoderSource &);
100        VideoEditorVideoEncoderSource &operator=(
101                const VideoEditorVideoEncoderSource &);
102
103        MediaBufferChain* mFirstBufferLink;
104        MediaBufferChain* mLastBufferLink;
105        int32_t           mNbBuffer;
106        bool              mIsEOS;
107        State             mState;
108        sp<MetaData>      mEncFormat;
109};
110
111sp<VideoEditorVideoEncoderSource> VideoEditorVideoEncoderSource::Create(
112    const sp<MetaData> &format) {
113
114    sp<VideoEditorVideoEncoderSource> aSource =
115        new VideoEditorVideoEncoderSource(format);
116    return aSource;
117}
118
119VideoEditorVideoEncoderSource::VideoEditorVideoEncoderSource(
120    const sp<MetaData> &format):
121        mFirstBufferLink(NULL),
122        mLastBufferLink(NULL),
123        mNbBuffer(0),
124        mIsEOS(false),
125        mState(CREATED),
126        mEncFormat(format) {
127    LOGV("VideoEditorVideoEncoderSource::VideoEditorVideoEncoderSource");
128}
129
130VideoEditorVideoEncoderSource::~VideoEditorVideoEncoderSource() {
131
132    // Safety clean up
133    if( STARTED == mState ) {
134        stop();
135    }
136}
137
138status_t VideoEditorVideoEncoderSource::start(MetaData *meta) {
139    status_t err = OK;
140
141    LOGV("VideoEditorVideoEncoderSource::start() begin");
142
143    if( CREATED != mState ) {
144        LOGV("VideoEditorVideoEncoderSource::start: invalid state %d", mState);
145        return UNKNOWN_ERROR;
146    }
147    mState = STARTED;
148
149    LOGV("VideoEditorVideoEncoderSource::start() END (0x%x)", err);
150    return err;
151}
152
153status_t VideoEditorVideoEncoderSource::stop() {
154    status_t err = OK;
155
156    LOGV("VideoEditorVideoEncoderSource::stop() begin");
157
158    if( STARTED != mState ) {
159        LOGV("VideoEditorVideoEncoderSource::stop: invalid state %d", mState);
160        return UNKNOWN_ERROR;
161    }
162
163    // Release the buffer chain
164    int32_t i = 0;
165    MediaBufferChain* tmpLink = NULL;
166    while( mFirstBufferLink ) {
167        i++;
168        tmpLink = mFirstBufferLink;
169        mFirstBufferLink = mFirstBufferLink->nextLink;
170        delete tmpLink;
171    }
172    LOGV("VideoEditorVideoEncoderSource::stop : %d buffer remained", i);
173    mFirstBufferLink = NULL;
174    mLastBufferLink = NULL;
175
176    mState = CREATED;
177
178    LOGV("VideoEditorVideoEncoderSource::stop() END (0x%x)", err);
179    return err;
180}
181
182sp<MetaData> VideoEditorVideoEncoderSource::getFormat() {
183
184    LOGV("VideoEditorVideoEncoderSource::getFormat");
185    return mEncFormat;
186}
187
188status_t VideoEditorVideoEncoderSource::read(MediaBuffer **buffer,
189        const ReadOptions *options) {
190    MediaSource::ReadOptions readOptions;
191    status_t err = OK;
192    MediaBufferChain* tmpLink = NULL;
193
194    LOGV("VideoEditorVideoEncoderSource::read() begin");
195
196    if ( STARTED != mState ) {
197        LOGV("VideoEditorVideoEncoderSource::read: invalid state %d", mState);
198        return UNKNOWN_ERROR;
199    }
200
201    // Get a buffer from the chain
202    if ( NULL == mFirstBufferLink ) {
203        *buffer = NULL;
204        if( mIsEOS ) {
205            LOGV("VideoEditorVideoEncoderSource::read : EOS");
206            return ERROR_END_OF_STREAM;
207        } else {
208            LOGV("VideoEditorVideoEncoderSource::read: no buffer available");
209            return ERROR_END_OF_STREAM;
210        }
211    }
212    *buffer = mFirstBufferLink->buffer;
213    tmpLink = mFirstBufferLink;
214    mFirstBufferLink = mFirstBufferLink->nextLink;
215
216    if ( NULL == mFirstBufferLink ) {
217        mLastBufferLink = NULL;
218    }
219    delete tmpLink;
220    mNbBuffer--;
221
222    LOGV("VideoEditorVideoEncoderSource::read() END (0x%x)", err);
223    return err;
224}
225
226int32_t VideoEditorVideoEncoderSource::storeBuffer(MediaBuffer *buffer) {
227    status_t err = OK;
228
229    LOGV("VideoEditorVideoEncoderSource::storeBuffer() begin");
230
231    if( NULL == buffer ) {
232        LOGV("VideoEditorVideoEncoderSource::storeBuffer : reached EOS");
233        mIsEOS = true;
234    } else {
235        MediaBufferChain* newLink = new MediaBufferChain;
236        newLink->buffer = buffer;
237        newLink->nextLink = NULL;
238        if( NULL != mLastBufferLink ) {
239            mLastBufferLink->nextLink = newLink;
240        } else {
241            mFirstBufferLink = newLink;
242        }
243        mLastBufferLink = newLink;
244        mNbBuffer++;
245    }
246    LOGV("VideoEditorVideoEncoderSource::storeBuffer() end");
247    return mNbBuffer;
248}
249
250/**
251 ******************************************************************************
252 * structure VideoEditorVideoEncoder_Context
253 * @brief    This structure defines the context of the StageFright video encoder
254 *           shell
255 ******************************************************************************
256*/
257typedef enum {
258    CREATED   = 0x1,
259    OPENED    = 0x2,
260    STARTED   = 0x4,
261    BUFFERING = 0x8,
262    READING   = 0x10
263} VideoEditorVideoEncoder_State;
264
265typedef struct {
266    VideoEditorVideoEncoder_State     mState;
267    M4ENCODER_Format                  mFormat;
268    M4WRITER_DataInterface*           mWriterDataInterface;
269    M4VPP_apply_fct*                  mPreProcFunction;
270    M4VPP_Context                     mPreProcContext;
271    M4SYS_AccessUnit*                 mAccessUnit;
272    M4ENCODER_Params*                 mCodecParams;
273    M4ENCODER_Header                  mHeader;
274    H264MCS_ProcessEncodedNALU_fct*   mH264NALUPostProcessFct;
275    M4OSA_Context                     mH264NALUPostProcessCtx;
276    M4OSA_UInt32                      mLastCTS;
277    sp<VideoEditorVideoEncoderSource> mEncoderSource;
278    OMXClient                         mClient;
279    sp<MediaSource>                   mEncoder;
280    OMX_COLOR_FORMATTYPE              mEncoderColorFormat;
281
282    uint32_t                          mNbInputFrames;
283    double                            mFirstInputCts;
284    double                            mLastInputCts;
285    uint32_t                          mNbOutputFrames;
286    int64_t                           mFirstOutputCts;
287    int64_t                           mLastOutputCts;
288
289} VideoEditorVideoEncoder_Context;
290
291/********************
292 *      TOOLS       *
293 ********************/
294
295M4OSA_ERR VideoEditorVideoEncoder_getDSI(M4ENCODER_Context pContext,
296        sp<MetaData> metaData) {
297    M4OSA_ERR err = M4NO_ERROR;
298    VideoEditorVideoEncoder_Context*  pEncoderContext = M4OSA_NULL;
299    status_t result = OK;
300    int32_t nbBuffer = 0;
301    int32_t stride = 0;
302    int32_t height = 0;
303    int32_t framerate = 0;
304    int32_t isCodecConfig = 0;
305    size_t size = 0;
306    uint32_t codecFlags = 0;
307    MediaBuffer* inputBuffer = NULL;
308    MediaBuffer* outputBuffer = NULL;
309    sp<VideoEditorVideoEncoderSource> encoderSource = NULL;
310    sp<MediaSource> encoder = NULL;;
311    OMXClient client;
312
313    LOGV("VideoEditorVideoEncoder_getDSI begin");
314    // Input parameters check
315    VIDEOEDITOR_CHECK(M4OSA_NULL != pContext,       M4ERR_PARAMETER);
316    VIDEOEDITOR_CHECK(M4OSA_NULL != metaData.get(), M4ERR_PARAMETER);
317
318    pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
319    VIDEOEDITOR_CHECK(CREATED == pEncoderContext->mState, M4ERR_STATE);
320
321    // Create the encoder source
322    encoderSource = VideoEditorVideoEncoderSource::Create(metaData);
323    VIDEOEDITOR_CHECK(NULL != encoderSource.get(), M4ERR_STATE);
324
325    // Connect to the OMX client
326    result = client.connect();
327    VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
328
329    // Create the OMX codec
330    // VIDEOEDITOR_FORCECODEC MUST be defined here
331    codecFlags |= OMXCodec::VIDEOEDITOR_FORCECODEC;
332    encoder = OMXCodec::Create(client.interface(), metaData, true,
333        encoderSource, NULL, codecFlags);
334    VIDEOEDITOR_CHECK(NULL != encoder.get(), M4ERR_STATE);
335
336    /**
337     * Send fake frames and retrieve the DSI
338     */
339    // Send a fake frame to the source
340    metaData->findInt32(kKeyStride,     &stride);
341    metaData->findInt32(kKeyHeight,     &height);
342    metaData->findInt32(kKeySampleRate, &framerate);
343    size = (size_t)(stride*height*3)/2;
344    inputBuffer = new MediaBuffer(size);
345    inputBuffer->meta_data()->setInt64(kKeyTime, 0);
346    nbBuffer = encoderSource->storeBuffer(inputBuffer);
347    encoderSource->storeBuffer(NULL); // Signal EOS
348
349    // Call read once to get the DSI
350    result = encoder->start();;
351    VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
352    result = encoder->read(&outputBuffer, NULL);
353    VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
354    VIDEOEDITOR_CHECK(outputBuffer->meta_data()->findInt32(
355        kKeyIsCodecConfig, &isCodecConfig) && isCodecConfig, M4ERR_STATE);
356
357    VIDEOEDITOR_CHECK(M4OSA_NULL == pEncoderContext->mHeader.pBuf, M4ERR_STATE);
358    if ( M4ENCODER_kH264 == pEncoderContext->mFormat ) {
359        // For H264, format the DSI
360        result = buildAVCCodecSpecificData(
361            (uint8_t**)(&(pEncoderContext->mHeader.pBuf)),
362            (size_t*)(&(pEncoderContext->mHeader.Size)),
363            (const uint8_t*)outputBuffer->data() + outputBuffer->range_offset(),
364            outputBuffer->range_length(), encoder->getFormat().get());
365        outputBuffer->release();
366        VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
367    } else {
368        // For MPEG4, just copy the DSI
369        pEncoderContext->mHeader.Size =
370            (M4OSA_UInt32)outputBuffer->range_length();
371        SAFE_MALLOC(pEncoderContext->mHeader.pBuf, M4OSA_Int8,
372            pEncoderContext->mHeader.Size, "Encoder header");
373        memcpy((void *)pEncoderContext->mHeader.pBuf,
374            (void *)((M4OSA_MemAddr8)(outputBuffer->data())+outputBuffer->range_offset()),
375            pEncoderContext->mHeader.Size);
376        outputBuffer->release();
377    }
378
379    result = encoder->stop();
380    VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
381
382cleanUp:
383    // Destroy the graph
384    if ( encoder != NULL ) { encoder.clear(); }
385    client.disconnect();
386    if ( encoderSource != NULL ) { encoderSource.clear(); }
387    if ( M4NO_ERROR == err ) {
388        LOGV("VideoEditorVideoEncoder_getDSI no error");
389    } else {
390        LOGV("VideoEditorVideoEncoder_getDSI ERROR 0x%X", err);
391    }
392    LOGV("VideoEditorVideoEncoder_getDSI end");
393    return err;
394}
395/********************
396 * ENGINE INTERFACE *
397 ********************/
398
399M4OSA_ERR VideoEditorVideoEncoder_cleanup(M4ENCODER_Context pContext) {
400    M4OSA_ERR err = M4NO_ERROR;
401    VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
402
403    LOGV("VideoEditorVideoEncoder_cleanup begin");
404    // Input parameters check
405    VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
406
407    pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
408    VIDEOEDITOR_CHECK(CREATED == pEncoderContext->mState, M4ERR_STATE);
409
410    // Release memory
411    SAFE_FREE(pEncoderContext->mHeader.pBuf);
412    SAFE_FREE(pEncoderContext);
413    pContext = M4OSA_NULL;
414
415cleanUp:
416    if ( M4NO_ERROR == err ) {
417        LOGV("VideoEditorVideoEncoder_cleanup no error");
418    } else {
419        LOGV("VideoEditorVideoEncoder_cleanup ERROR 0x%X", err);
420    }
421    LOGV("VideoEditorVideoEncoder_cleanup end");
422    return err;
423}
424
425M4OSA_ERR VideoEditorVideoEncoder_init(M4ENCODER_Format format,
426        M4ENCODER_Context* pContext,
427        M4WRITER_DataInterface* pWriterDataInterface,
428        M4VPP_apply_fct* pVPPfct, M4VPP_Context pVPPctxt,
429        M4OSA_Void* pExternalAPI, M4OSA_Void* pUserData) {
430
431    M4OSA_ERR err = M4NO_ERROR;
432    VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
433
434    LOGV("VideoEditorVideoEncoder_init begin: format  %d", format);
435    // Input parameters check
436    VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
437    VIDEOEDITOR_CHECK(M4OSA_NULL != pWriterDataInterface, M4ERR_PARAMETER);
438    VIDEOEDITOR_CHECK(M4OSA_NULL != pVPPfct, M4ERR_PARAMETER);
439    VIDEOEDITOR_CHECK(M4OSA_NULL != pVPPctxt, M4ERR_PARAMETER);
440
441    // Context allocation & initialization
442    SAFE_MALLOC(pEncoderContext, VideoEditorVideoEncoder_Context, 1,
443        "VideoEditorVideoEncoder");
444    pEncoderContext->mState = CREATED;
445    pEncoderContext->mFormat = format;
446    pEncoderContext->mWriterDataInterface = pWriterDataInterface;
447    pEncoderContext->mPreProcFunction = pVPPfct;
448    pEncoderContext->mPreProcContext = pVPPctxt;
449
450    *pContext = pEncoderContext;
451
452cleanUp:
453    if ( M4NO_ERROR == err ) {
454        LOGV("VideoEditorVideoEncoder_init no error");
455    } else {
456        VideoEditorVideoEncoder_cleanup(pEncoderContext);
457        *pContext = M4OSA_NULL;
458        LOGV("VideoEditorVideoEncoder_init ERROR 0x%X", err);
459    }
460    LOGV("VideoEditorVideoEncoder_init end");
461    return err;
462}
463
464M4OSA_ERR VideoEditorVideoEncoder_init_H263(M4ENCODER_Context* pContext,
465        M4WRITER_DataInterface* pWriterDataInterface, M4VPP_apply_fct* pVPPfct,
466        M4VPP_Context pVPPctxt, M4OSA_Void* pExternalAPI, M4OSA_Void* pUserData)
467        {
468
469    return VideoEditorVideoEncoder_init(M4ENCODER_kH263, pContext,
470        pWriterDataInterface, pVPPfct, pVPPctxt, pExternalAPI, pUserData);
471}
472
473
474M4OSA_ERR VideoEditorVideoEncoder_init_MPEG4(M4ENCODER_Context* pContext,
475        M4WRITER_DataInterface* pWriterDataInterface, M4VPP_apply_fct* pVPPfct,
476        M4VPP_Context pVPPctxt, M4OSA_Void* pExternalAPI, M4OSA_Void* pUserData)
477        {
478
479    return VideoEditorVideoEncoder_init(M4ENCODER_kMPEG4, pContext,
480        pWriterDataInterface, pVPPfct, pVPPctxt, pExternalAPI, pUserData);
481}
482
483
484M4OSA_ERR VideoEditorVideoEncoder_init_H264(M4ENCODER_Context* pContext,
485        M4WRITER_DataInterface* pWriterDataInterface, M4VPP_apply_fct* pVPPfct,
486        M4VPP_Context pVPPctxt, M4OSA_Void* pExternalAPI, M4OSA_Void* pUserData)
487        {
488
489    return VideoEditorVideoEncoder_init(M4ENCODER_kH264, pContext,
490        pWriterDataInterface, pVPPfct, pVPPctxt, pExternalAPI, pUserData);
491}
492
493M4OSA_ERR VideoEditorVideoEncoder_close(M4ENCODER_Context pContext) {
494    M4OSA_ERR err = M4NO_ERROR;
495    VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
496
497    LOGV("VideoEditorVideoEncoder_close begin");
498    // Input parameters check
499    VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
500
501    pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
502    VIDEOEDITOR_CHECK(OPENED == pEncoderContext->mState, M4ERR_STATE);
503
504    // Release memory
505    SAFE_FREE(pEncoderContext->mCodecParams);
506
507    // Destroy the graph
508    pEncoderContext->mEncoder.clear();
509    pEncoderContext->mClient.disconnect();
510    pEncoderContext->mEncoderSource.clear();
511
512    // Set the new state
513    pEncoderContext->mState = CREATED;
514
515cleanUp:
516    if( M4NO_ERROR == err ) {
517        LOGV("VideoEditorVideoEncoder_close no error");
518    } else {
519        LOGV("VideoEditorVideoEncoder_close ERROR 0x%X", err);
520    }
521    LOGV("VideoEditorVideoEncoder_close end");
522    return err;
523}
524
525
526M4OSA_ERR VideoEditorVideoEncoder_open(M4ENCODER_Context pContext,
527        M4SYS_AccessUnit* pAU, M4OSA_Void* pParams) {
528    M4OSA_ERR err = M4NO_ERROR;
529    VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
530    M4ENCODER_Params* pCodecParams = M4OSA_NULL;
531    status_t result = OK;
532    sp<MetaData> encoderMetadata = NULL;
533    const char* mime = NULL;
534    int32_t iProfile = 0;
535    int32_t iFrameRate = 0;
536    uint32_t codecFlags = 0;
537
538    LOGV(">>> VideoEditorVideoEncoder_open begin");
539    // Input parameters check
540    VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
541    VIDEOEDITOR_CHECK(M4OSA_NULL != pAU,      M4ERR_PARAMETER);
542    VIDEOEDITOR_CHECK(M4OSA_NULL != pParams,  M4ERR_PARAMETER);
543
544    pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
545    pCodecParams = (M4ENCODER_Params*)pParams;
546    VIDEOEDITOR_CHECK(CREATED == pEncoderContext->mState, M4ERR_STATE);
547
548    // Context initialization
549    pEncoderContext->mAccessUnit = pAU;
550
551    // Allocate & initialize the encoding parameters
552    SAFE_MALLOC(pEncoderContext->mCodecParams, M4ENCODER_Params, 1,
553        "VideoEditorVideoEncoder");
554
555
556    pEncoderContext->mCodecParams->InputFormat = pCodecParams->InputFormat;
557    pEncoderContext->mCodecParams->InputFrameWidth =
558        pCodecParams->InputFrameWidth;
559    pEncoderContext->mCodecParams->InputFrameHeight =
560        pCodecParams->InputFrameHeight;
561    pEncoderContext->mCodecParams->FrameWidth = pCodecParams->FrameWidth;
562    pEncoderContext->mCodecParams->FrameHeight = pCodecParams->FrameHeight;
563    pEncoderContext->mCodecParams->Bitrate = pCodecParams->Bitrate;
564    pEncoderContext->mCodecParams->FrameRate = pCodecParams->FrameRate;
565    pEncoderContext->mCodecParams->Format = pCodecParams->Format;
566
567    // Check output format consistency and resolution
568    VIDEOEDITOR_CHECK(
569        pEncoderContext->mCodecParams->Format == pEncoderContext->mFormat,
570        M4ERR_PARAMETER);
571    VIDEOEDITOR_CHECK(0 == pEncoderContext->mCodecParams->FrameWidth  % 16,
572        M4ERR_PARAMETER);
573    VIDEOEDITOR_CHECK(0 == pEncoderContext->mCodecParams->FrameHeight % 16,
574        M4ERR_PARAMETER);
575
576    /**
577     * StageFright graph building
578     */
579
580    // Create the meta data for the encoder
581    encoderMetadata = new MetaData;
582    switch( pEncoderContext->mCodecParams->Format ) {
583        case M4ENCODER_kH263:
584            mime     = MEDIA_MIMETYPE_VIDEO_H263;
585            iProfile = OMX_VIDEO_H263ProfileBaseline;
586            break;
587        case M4ENCODER_kMPEG4:
588            mime     = MEDIA_MIMETYPE_VIDEO_MPEG4;
589            iProfile = OMX_VIDEO_MPEG4ProfileSimple;
590            break;
591        case M4ENCODER_kH264:
592            mime     = MEDIA_MIMETYPE_VIDEO_AVC;
593            iProfile = OMX_VIDEO_AVCProfileBaseline;
594            break;
595        default:
596            VIDEOEDITOR_CHECK(!"VideoEncoder_open : incorrect input format",
597                M4ERR_PARAMETER);
598            break;
599    }
600    encoderMetadata->setCString(kKeyMIMEType, mime);
601    encoderMetadata->setInt32(kKeyVideoProfile, iProfile);
602    encoderMetadata->setInt32(kKeyWidth,
603        (int32_t)pEncoderContext->mCodecParams->FrameWidth);
604    encoderMetadata->setInt32(kKeyStride,
605        (int32_t)pEncoderContext->mCodecParams->FrameWidth);
606    encoderMetadata->setInt32(kKeyHeight,
607        (int32_t)pEncoderContext->mCodecParams->FrameHeight);
608    encoderMetadata->setInt32(kKeySliceHeight,
609        (int32_t)pEncoderContext->mCodecParams->FrameHeight);
610
611    switch( pEncoderContext->mCodecParams->FrameRate ) {
612        case M4ENCODER_k5_FPS:    iFrameRate = 5;  break;
613        case M4ENCODER_k7_5_FPS:  iFrameRate = 8;  break;
614        case M4ENCODER_k10_FPS:   iFrameRate = 10; break;
615        case M4ENCODER_k12_5_FPS: iFrameRate = 13; break;
616        case M4ENCODER_k15_FPS:   iFrameRate = 15; break;
617        case M4ENCODER_k20_FPS:   iFrameRate = 20; break;
618        case M4ENCODER_k25_FPS:   iFrameRate = 25; break;
619        case M4ENCODER_k30_FPS:   iFrameRate = 30; break;
620        case M4ENCODER_kVARIABLE_FPS:
621            iFrameRate = 30;
622            LOGI("Frame rate set to M4ENCODER_kVARIABLE_FPS: set to 30");
623          break;
624        case M4ENCODER_kUSE_TIMESCALE:
625            iFrameRate = 30;
626            LOGI("Frame rate set to M4ENCODER_kUSE_TIMESCALE:  set to 30");
627            break;
628
629        default:
630            VIDEOEDITOR_CHECK(!"VideoEncoder_open:incorrect framerate",
631                M4ERR_STATE);
632            break;
633    }
634    encoderMetadata->setInt32(kKeyFrameRate, iFrameRate);
635    encoderMetadata->setInt32(kKeyBitRate,
636        (int32_t)pEncoderContext->mCodecParams->Bitrate);
637    encoderMetadata->setInt32(kKeyIFramesInterval, 1);
638
639    pEncoderContext->mEncoderColorFormat = VIDEOEDITOR_ENCODER_COLOR_FORMAT;
640    encoderMetadata->setInt32(kKeyColorFormat,
641        pEncoderContext->mEncoderColorFormat);
642
643#ifdef VIDEOEDITOR_ENCODER_GET_DSI_AT_CREATION
644    // Get the encoder DSI
645    err = VideoEditorVideoEncoder_getDSI(pEncoderContext, encoderMetadata);
646    VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
647#endif /* VIDEOEDITOR_ENCODER_GET_DSI_AT_CREATION */
648
649    // Create the encoder source
650    pEncoderContext->mEncoderSource = VideoEditorVideoEncoderSource::Create(
651        encoderMetadata);
652    VIDEOEDITOR_CHECK(
653        NULL != pEncoderContext->mEncoderSource.get(), M4ERR_STATE);
654
655    // Connect to the OMX client
656    result = pEncoderContext->mClient.connect();
657    VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
658
659    // Create the OMX codec
660#ifdef VIDEOEDITOR_FORCECODEC
661    codecFlags |= OMXCodec::VIDEOEDITOR_FORCECODEC;
662#endif /* VIDEOEDITOR_FORCECODEC */
663    pEncoderContext->mEncoder = OMXCodec::Create(
664        pEncoderContext->mClient.interface(), encoderMetadata, true,
665        pEncoderContext->mEncoderSource, NULL, codecFlags);
666    VIDEOEDITOR_CHECK(NULL != pEncoderContext->mEncoder.get(), M4ERR_STATE);
667    LOGV("VideoEditorVideoEncoder_open : DONE");
668
669    // Set the new state
670    pEncoderContext->mState = OPENED;
671
672cleanUp:
673    if( M4NO_ERROR == err ) {
674        LOGV("VideoEditorVideoEncoder_open no error");
675    } else {
676        VideoEditorVideoEncoder_close(pEncoderContext);
677        LOGV("VideoEditorVideoEncoder_open ERROR 0x%X", err);
678    }
679    LOGV("VideoEditorVideoEncoder_open end");
680    return err;
681}
682
683M4OSA_ERR VideoEditorVideoEncoder_processInputBuffer(
684        M4ENCODER_Context pContext, M4OSA_Double Cts,
685        M4OSA_Bool bReachedEOS) {
686    M4OSA_ERR err = M4NO_ERROR;
687    VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
688    M4VIFI_ImagePlane pOutPlane[3];
689    MediaBuffer* buffer = NULL;
690    int32_t nbBuffer = 0;
691
692    LOGV("VideoEditorVideoEncoder_processInputBuffer begin: cts  %f", Cts);
693    // Input parameters check
694    VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
695
696    pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
697    pOutPlane[0].pac_data = M4OSA_NULL;
698    pOutPlane[1].pac_data = M4OSA_NULL;
699    pOutPlane[2].pac_data = M4OSA_NULL;
700
701    if ( M4OSA_FALSE == bReachedEOS ) {
702        M4OSA_UInt32 sizeY = pEncoderContext->mCodecParams->FrameWidth *
703            pEncoderContext->mCodecParams->FrameHeight;
704        M4OSA_UInt32 sizeU = sizeY >> 2;
705        M4OSA_UInt32 size  = sizeY + 2*sizeU;
706        M4OSA_UInt8* pData = M4OSA_NULL;
707        buffer = new MediaBuffer((size_t)size);
708        pData = (M4OSA_UInt8*)buffer->data() + buffer->range_offset();
709
710        // Prepare the output image for pre-processing
711        pOutPlane[0].u_width   = pEncoderContext->mCodecParams->FrameWidth;
712        pOutPlane[0].u_height  = pEncoderContext->mCodecParams->FrameHeight;
713        pOutPlane[0].u_topleft = 0;
714        pOutPlane[0].u_stride  = pOutPlane[0].u_width;
715        pOutPlane[1].u_width   = pOutPlane[0].u_width/2;
716        pOutPlane[1].u_height  = pOutPlane[0].u_height/2;
717        pOutPlane[1].u_topleft = 0;
718        pOutPlane[1].u_stride  = pOutPlane[0].u_stride/2;
719        pOutPlane[2].u_width   = pOutPlane[1].u_width;
720        pOutPlane[2].u_height  = pOutPlane[1].u_height;
721        pOutPlane[2].u_topleft = 0;
722        pOutPlane[2].u_stride  = pOutPlane[1].u_stride;
723
724        switch( pEncoderContext->mEncoderColorFormat ) {
725            case OMX_COLOR_FormatYUV420Planar:
726                pOutPlane[0].pac_data = pData;
727                pOutPlane[1].pac_data = pData + sizeY;
728                pOutPlane[2].pac_data = pData + sizeY + sizeU;
729            break;
730            case OMX_COLOR_FormatYUV420SemiPlanar:
731                pOutPlane[0].pac_data = pData;
732                SAFE_MALLOC(pOutPlane[1].pac_data, M4VIFI_UInt8,
733                    pOutPlane[1].u_height*pOutPlane[1].u_stride,"OutputPlaneU");
734                SAFE_MALLOC(pOutPlane[2].pac_data, M4VIFI_UInt8,
735                    pOutPlane[2].u_height*pOutPlane[2].u_stride,"OutputPlaneV");
736            break;
737            default:
738                LOGV("VideoEditorVideoEncoder_processInputBuffer : unsupported "
739                    "color format 0x%X", pEncoderContext->mEncoderColorFormat);
740                VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_PARAMETER);
741            break;
742        }
743
744        // Apply pre-processing
745        err = pEncoderContext->mPreProcFunction(
746            pEncoderContext->mPreProcContext, M4OSA_NULL, pOutPlane);
747        VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
748
749        // Convert to MediaBuffer format if necessary
750        if( OMX_COLOR_FormatYUV420SemiPlanar == \
751                pEncoderContext->mEncoderColorFormat ) {
752            M4OSA_UInt8* pTmpData = M4OSA_NULL;
753            pTmpData = pData + sizeY;
754            // Highly unoptimized copy...
755            for( M4OSA_UInt32 i=0; i<sizeU; i++ ) {
756                *pTmpData = pOutPlane[2].pac_data[i]; pTmpData++;
757                *pTmpData = pOutPlane[1].pac_data[i]; pTmpData++;
758            }
759        }
760
761        // Set the metadata
762        buffer->meta_data()->setInt64(kKeyTime, (int64_t)(Cts*1000));
763    }
764
765    // Push the buffer to the source, a NULL buffer, notifies the source of EOS
766    nbBuffer = pEncoderContext->mEncoderSource->storeBuffer(buffer);
767    if ( VIDEOEDITOR_MIN_BUFFER_NB > nbBuffer ) {
768        LOGV("VideoEncoder_processInputBuffer not enough source buffer"
769        "%d", nbBuffer);
770        err = M4WAR_SF_LOW_BUFFER;
771    }
772
773cleanUp:
774    if ( OMX_COLOR_FormatYUV420SemiPlanar == \
775            pEncoderContext->mEncoderColorFormat ) {
776        // Y plane has not been allocated
777        if ( pOutPlane[1].pac_data ) {
778            SAFE_FREE(pOutPlane[1].pac_data);
779        }
780        if ( pOutPlane[2].pac_data ) {
781            SAFE_FREE(pOutPlane[2].pac_data);
782        }
783    }
784    if ( (M4NO_ERROR == err) || (M4WAR_SF_LOW_BUFFER == err) ) {
785        LOGV("VideoEditorVideoEncoder_processInputBuffer error 0x%X", err);
786    } else {
787        if( NULL != buffer ) {
788            buffer->release();
789        }
790        LOGV("VideoEditorVideoEncoder_processInputBuffer ERROR 0x%X", err);
791    }
792    LOGV("VideoEditorVideoEncoder_processInputBuffer end");
793    return err;
794}
795
796M4OSA_ERR VideoEditorVideoEncoder_processOutputBuffer(
797        M4ENCODER_Context pContext, MediaBuffer* buffer) {
798    M4OSA_ERR err = M4NO_ERROR;
799    VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
800    M4OSA_UInt32 Cts = 0;
801    int32_t i32Tmp = 0;
802    int64_t i64Tmp = 0;
803    status_t result = OK;
804
805    LOGV("VideoEditorVideoEncoder_processOutputBuffer begin");
806    // Input parameters check
807    VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
808    VIDEOEDITOR_CHECK(M4OSA_NULL != buffer,   M4ERR_PARAMETER);
809
810    pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
811
812    // Process the returned AU
813    if ( 0 == buffer->range_length() ) {
814        // Encoder has no data yet, nothing unusual
815        LOGV("VideoEditorVideoEncoder_processOutputBuffer : buffer is empty");
816        goto cleanUp;
817    }
818    VIDEOEDITOR_CHECK(0 == ((M4OSA_UInt32)buffer->data())%4, M4ERR_PARAMETER);
819    VIDEOEDITOR_CHECK(buffer->meta_data().get(), M4ERR_PARAMETER);
820    if ( buffer->meta_data()->findInt32(kKeyIsCodecConfig, &i32Tmp) && i32Tmp ){
821        {   // Display the DSI
822            LOGV("VideoEditorVideoEncoder_processOutputBuffer DSI %d",
823                buffer->range_length());
824            uint8_t* tmp = (uint8_t*)(buffer->data());
825            for( uint32_t i=0; i<buffer->range_length(); i++ ) {
826                LOGV("DSI [%d] %.2X", i, tmp[i]);
827            }
828        }
829
830#ifndef VIDEOEDITOR_ENCODER_GET_DSI_AT_CREATION
831        VIDEOEDITOR_CHECK(M4OSA_NULL == pEncoderContext->mHeader.pBuf,
832            M4ERR_STATE);
833        if ( M4ENCODER_kH264 == pEncoderContext->mFormat ) {
834            result = buildAVCCodecSpecificData(
835                (uint8_t**)(&(pEncoderContext->mHeader.pBuf)),
836                (size_t*)(&(pEncoderContext->mHeader.Size)),
837                (const uint8_t *)buffer->data() + buffer->range_offset(),
838                buffer->range_length(),
839                pEncoderContext->mEncoder->getFormat().get());
840        } else {
841            pEncoderContext->mHeader.Size =
842                (M4OSA_UInt32)buffer->range_length();
843            SAFE_MALLOC(pEncoderContext->mHeader.pBuf, M4OSA_Int8,
844                pEncoderContext->mHeader.Size, "Encoder header");
845            memcpy((void *)pEncoderContext->mHeader.pBuf,
846                (void *)((M4OSA_MemAddr8)(buffer->data())+buffer->range_offset()),
847                pEncoderContext->mHeader.Size);
848        }
849#endif /* VIDEOEDITOR_ENCODER_GET_DSI_AT_CREATION */
850    } else {
851        // Check the CTS
852        VIDEOEDITOR_CHECK(buffer->meta_data()->findInt64(kKeyTime, &i64Tmp),
853            M4ERR_STATE);
854
855        pEncoderContext->mNbOutputFrames++;
856        if ( 0 > pEncoderContext->mFirstOutputCts ) {
857            pEncoderContext->mFirstOutputCts = i64Tmp;
858        }
859        pEncoderContext->mLastOutputCts = i64Tmp;
860
861        Cts = (M4OSA_Int32)(i64Tmp/1000);
862        LOGV("[TS_CHECK] VI/ENC WRITE frame %d @ %lld -> %d (last %d)",
863            pEncoderContext->mNbOutputFrames, i64Tmp, Cts,
864            pEncoderContext->mLastCTS);
865        if ( Cts < pEncoderContext->mLastCTS ) {
866            LOGV("VideoEncoder_processOutputBuffer WARNING : Cts is going "
867            "backwards %d < %d", Cts, pEncoderContext->mLastCTS);
868            goto cleanUp;
869        }
870        LOGV("VideoEditorVideoEncoder_processOutputBuffer : %d %d",
871            Cts, pEncoderContext->mLastCTS);
872
873        // Retrieve the AU container
874        err = pEncoderContext->mWriterDataInterface->pStartAU(
875            pEncoderContext->mWriterDataInterface->pWriterContext,
876            pEncoderContext->mAccessUnit->stream->streamID,
877            pEncoderContext->mAccessUnit);
878        VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
879
880        // Format the AU
881        VIDEOEDITOR_CHECK(
882            buffer->range_length() <= pEncoderContext->mAccessUnit->size,
883            M4ERR_PARAMETER);
884        // Remove H264 AU start code
885        if ( M4ENCODER_kH264 == pEncoderContext->mFormat ) {
886            if (!memcmp((const uint8_t *)buffer->data() + \
887                    buffer->range_offset(), "\x00\x00\x00\x01", 4) ) {
888                buffer->set_range(buffer->range_offset() + 4,
889                    buffer->range_length() - 4);
890            }
891        }
892
893        if ( (M4ENCODER_kH264 == pEncoderContext->mFormat) &&
894            (M4OSA_NULL != pEncoderContext->mH264NALUPostProcessFct) ) {
895        // H264 trimming case, NALU post processing is needed
896        M4OSA_Int32 outputSize = pEncoderContext->mAccessUnit->size;
897        err = pEncoderContext->mH264NALUPostProcessFct(
898            pEncoderContext->mH264NALUPostProcessCtx,
899            (M4OSA_UInt8*)buffer->data()+buffer->range_offset(),
900            buffer->range_length(),
901            (M4OSA_UInt8*)pEncoderContext->mAccessUnit->dataAddress,
902            &outputSize);
903        VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
904        pEncoderContext->mAccessUnit->size = (M4OSA_UInt32)outputSize;
905        } else {
906            // The AU can just be copied
907            memcpy((void *)pEncoderContext->mAccessUnit->\
908                dataAddress, (void *)((M4OSA_MemAddr8)(buffer->data())+buffer->\
909                range_offset()), buffer->range_length());
910            pEncoderContext->mAccessUnit->size =
911                (M4OSA_UInt32)buffer->range_length();
912        }
913
914        if ( buffer->meta_data()->findInt32(kKeyIsSyncFrame,&i32Tmp) && i32Tmp){
915            pEncoderContext->mAccessUnit->attribute = AU_RAP;
916        } else {
917            pEncoderContext->mAccessUnit->attribute = AU_P_Frame;
918        }
919        pEncoderContext->mLastCTS = Cts;
920        pEncoderContext->mAccessUnit->CTS = Cts;
921        pEncoderContext->mAccessUnit->DTS = Cts;
922
923        LOGV("VideoEditorVideoEncoder_processOutputBuffer: AU @ 0x%X 0x%X %d %d",
924            pEncoderContext->mAccessUnit->dataAddress,
925            *pEncoderContext->mAccessUnit->dataAddress,
926            pEncoderContext->mAccessUnit->size,
927            pEncoderContext->mAccessUnit->CTS);
928
929        // Write the AU
930        err = pEncoderContext->mWriterDataInterface->pProcessAU(
931            pEncoderContext->mWriterDataInterface->pWriterContext,
932            pEncoderContext->mAccessUnit->stream->streamID,
933            pEncoderContext->mAccessUnit);
934        VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
935    }
936
937cleanUp:
938    buffer->release();
939    if( M4NO_ERROR == err ) {
940        LOGV("VideoEditorVideoEncoder_processOutputBuffer no error");
941    } else {
942        SAFE_FREE(pEncoderContext->mHeader.pBuf);
943        pEncoderContext->mHeader.Size = 0;
944        LOGV("VideoEditorVideoEncoder_processOutputBuffer ERROR 0x%X", err);
945    }
946    LOGV("VideoEditorVideoEncoder_processOutputBuffer end");
947    return err;
948}
949
950M4OSA_ERR VideoEditorVideoEncoder_encode(M4ENCODER_Context pContext,
951        M4VIFI_ImagePlane* pInPlane, M4OSA_Double Cts,
952        M4ENCODER_FrameMode FrameMode) {
953    M4OSA_ERR err = M4NO_ERROR;
954    VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
955    status_t result = OK;
956    MediaBuffer* outputBuffer = NULL;
957
958    LOGV("VideoEditorVideoEncoder_encode 0x%X %f %d", pInPlane, Cts, FrameMode);
959    VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
960
961    pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
962    if ( STARTED == pEncoderContext->mState ) {
963        pEncoderContext->mState = BUFFERING;
964    }
965    VIDEOEDITOR_CHECK(
966        (BUFFERING | READING) & pEncoderContext->mState, M4ERR_STATE);
967
968    pEncoderContext->mNbInputFrames++;
969    if ( 0 > pEncoderContext->mFirstInputCts ) {
970        pEncoderContext->mFirstInputCts = Cts;
971    }
972    pEncoderContext->mLastInputCts = Cts;
973
974    LOGV("VideoEditorVideoEncoder_encode 0x%X %d %f (%d)", pInPlane, FrameMode,
975        Cts, pEncoderContext->mLastCTS);
976
977    // Push the input buffer to the encoder source
978    err = VideoEditorVideoEncoder_processInputBuffer(pEncoderContext, Cts,
979        M4OSA_FALSE);
980    VIDEOEDITOR_CHECK((M4NO_ERROR == err) || (M4WAR_SF_LOW_BUFFER == err), err);
981
982    // Notify the source in case of EOS
983    if ( M4ENCODER_kLastFrame == FrameMode ) {
984        err = VideoEditorVideoEncoder_processInputBuffer(
985            pEncoderContext, 0, M4OSA_TRUE);
986        VIDEOEDITOR_CHECK((M4NO_ERROR == err) || (M4WAR_SF_LOW_BUFFER == err),
987            err);
988    }
989
990    if ( BUFFERING == pEncoderContext->mState ) {
991        if ( M4WAR_SF_LOW_BUFFER == err ) {
992            // Insufficient prefetch, do not encode
993            err = M4NO_ERROR;
994            goto cleanUp;
995        } else {
996            // Prefetch is complete, start reading
997            pEncoderContext->mState = READING;
998        }
999    }
1000    // Read
1001    result = pEncoderContext->mEncoder->read(&outputBuffer, NULL);
1002    if( OK != result ) {
1003        LOGV("VideoEditorVideoEncoder_encode: encoder returns 0x%X", result);
1004    }
1005
1006    if( ERROR_END_OF_STREAM == result ) {
1007        if( outputBuffer != NULL ) {
1008            LOGV("VideoEditorVideoEncoder_encode : EOS w/ buffer");
1009        }
1010        VIDEOEDITOR_CHECK(0 == VIDEOEDITOR_MIN_BUFFER_NB, M4ERR_STATE);
1011        // No output provided here, just exit
1012        goto cleanUp;
1013    }
1014    VIDEOEDITOR_CHECK((OK == result) || (ERROR_END_OF_STREAM == result),
1015        M4ERR_STATE);
1016
1017    // Provide the encoded AU to the writer
1018    err = VideoEditorVideoEncoder_processOutputBuffer(pEncoderContext,
1019        outputBuffer);
1020    VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
1021
1022cleanUp:
1023    if( M4NO_ERROR == err ) {
1024        LOGV("VideoEditorVideoEncoder_encode no error");
1025    } else {
1026        LOGV("VideoEditorVideoEncoder_encode ERROR 0x%X", err);
1027    }
1028    LOGV("VideoEditorVideoEncoder_encode end");
1029    return err;
1030}
1031
1032M4OSA_ERR VideoEditorVideoEncoder_start(M4ENCODER_Context pContext) {
1033    M4OSA_ERR                  err             = M4NO_ERROR;
1034    VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
1035    status_t                   result          = OK;
1036
1037    LOGV("VideoEditorVideoEncoder_start begin");
1038    // Input parameters check
1039    VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
1040
1041    pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
1042    VIDEOEDITOR_CHECK(OPENED == pEncoderContext->mState, M4ERR_STATE);
1043
1044    pEncoderContext->mNbInputFrames  = 0;
1045    pEncoderContext->mFirstInputCts  = -1.0;
1046    pEncoderContext->mLastInputCts   = -1.0;
1047    pEncoderContext->mNbOutputFrames = 0;
1048    pEncoderContext->mFirstOutputCts = -1;
1049    pEncoderContext->mLastOutputCts  = -1;
1050
1051    result = pEncoderContext->mEncoder->start();
1052    VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
1053
1054    // Set the new state
1055    pEncoderContext->mState = STARTED;
1056
1057cleanUp:
1058    if ( M4NO_ERROR == err ) {
1059        LOGV("VideoEditorVideoEncoder_start no error");
1060    } else {
1061        LOGV("VideoEditorVideoEncoder_start ERROR 0x%X", err);
1062    }
1063    LOGV("VideoEditorVideoEncoder_start end");
1064    return err;
1065}
1066
1067M4OSA_ERR VideoEditorVideoEncoder_stop(M4ENCODER_Context pContext) {
1068    M4OSA_ERR err = M4NO_ERROR;
1069    VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
1070    MediaBuffer* outputBuffer = NULL;
1071    status_t result = OK;
1072
1073    LOGV("VideoEditorVideoEncoder_stop begin");
1074    // Input parameters check
1075    VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
1076    pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
1077
1078    // Process the remaining buffers if necessary
1079    if ( (BUFFERING | READING) & pEncoderContext->mState ) {
1080        // Send EOS again just in case
1081        err = VideoEditorVideoEncoder_processInputBuffer(pEncoderContext, 0,
1082            M4OSA_TRUE);
1083        VIDEOEDITOR_CHECK((M4NO_ERROR == err) || (M4WAR_SF_LOW_BUFFER == err),
1084            err);
1085        while( OK == result ) {
1086            result = pEncoderContext->mEncoder->read(&outputBuffer, NULL);
1087            if ( OK == result ) {
1088                err = VideoEditorVideoEncoder_processOutputBuffer(
1089                    pEncoderContext, outputBuffer);
1090                VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
1091            }
1092        }
1093        pEncoderContext->mState = STARTED;
1094    }
1095
1096    // Stop the graph module if necessary
1097    if ( STARTED == pEncoderContext->mState ) {
1098        pEncoderContext->mEncoder->stop();
1099        pEncoderContext->mState = OPENED;
1100    }
1101
1102    if (pEncoderContext->mNbInputFrames != pEncoderContext->mNbOutputFrames) {
1103        LOGW("Some frames were not encoded: input(%d) != output(%d)",
1104            pEncoderContext->mNbInputFrames, pEncoderContext->mNbOutputFrames);
1105    }
1106
1107cleanUp:
1108    if ( M4NO_ERROR == err ) {
1109        LOGV("VideoEditorVideoEncoder_stop no error");
1110    } else {
1111        LOGV("VideoEditorVideoEncoder_stop ERROR 0x%X", err);
1112    }
1113    LOGV("VideoEditorVideoEncoder_stop end");
1114    return err;
1115}
1116
1117M4OSA_ERR VideoEditorVideoEncoder_regulBitRate(M4ENCODER_Context pContext) {
1118    LOGW("regulBitRate is not implemented");
1119    return M4NO_ERROR;
1120}
1121
1122M4OSA_ERR VideoEditorVideoEncoder_setOption(M4ENCODER_Context pContext,
1123        M4OSA_UInt32 optionID, M4OSA_DataOption optionValue) {
1124    M4OSA_ERR err = M4NO_ERROR;
1125    VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
1126
1127    LOGV("VideoEditorVideoEncoder_setOption start optionID 0x%X", optionID);
1128    // Input parameters check
1129    VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
1130
1131    pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
1132
1133    switch( optionID ) {
1134        case M4ENCODER_kOptionID_SetH264ProcessNALUfctsPtr:
1135            pEncoderContext->mH264NALUPostProcessFct =
1136                (H264MCS_ProcessEncodedNALU_fct*)optionValue;
1137            break;
1138        case M4ENCODER_kOptionID_H264ProcessNALUContext:
1139            pEncoderContext->mH264NALUPostProcessCtx =
1140                (M4OSA_Context)optionValue;
1141            break;
1142        default:
1143            LOGV("VideoEditorVideoEncoder_setOption: unsupported optionId 0x%X",
1144                optionID);
1145            VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_BAD_OPTION_ID);
1146            break;
1147    }
1148
1149cleanUp:
1150    if ( M4NO_ERROR == err ) {
1151        LOGV("VideoEditorVideoEncoder_setOption no error");
1152    } else {
1153        LOGV("VideoEditorVideoEncoder_setOption ERROR 0x%X", err);
1154    }
1155    LOGV("VideoEditorVideoEncoder_setOption end");
1156    return err;
1157}
1158
1159M4OSA_ERR VideoEditorVideoEncoder_getOption(M4ENCODER_Context pContext,
1160        M4OSA_UInt32 optionID, M4OSA_DataOption optionValue) {
1161    M4OSA_ERR err = M4NO_ERROR;
1162    VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
1163
1164    LOGV("VideoEditorVideoEncoder_getOption begin optinId 0x%X", optionID);
1165    // Input parameters check
1166    VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
1167    pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
1168
1169    switch( optionID ) {
1170        case M4ENCODER_kOptionID_EncoderHeader:
1171            VIDEOEDITOR_CHECK(
1172                    M4OSA_NULL != pEncoderContext->mHeader.pBuf, M4ERR_STATE);
1173            *(M4ENCODER_Header**)optionValue = &(pEncoderContext->mHeader);
1174            break;
1175        default:
1176            LOGV("VideoEditorVideoEncoder_getOption: unsupported optionId 0x%X",
1177                optionID);
1178            VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_BAD_OPTION_ID);
1179            break;
1180    }
1181
1182cleanUp:
1183    if ( M4NO_ERROR == err ) {
1184        LOGV("VideoEditorVideoEncoder_getOption no error");
1185    } else {
1186        LOGV("VideoEditorVideoEncoder_getOption ERROR 0x%X", err);
1187    }
1188    return err;
1189}
1190
1191M4OSA_ERR VideoEditorVideoEncoder_getInterface(M4ENCODER_Format format,
1192        M4ENCODER_Format* pFormat,
1193        M4ENCODER_GlobalInterface** pEncoderInterface, M4ENCODER_OpenMode mode){
1194    M4OSA_ERR err = M4NO_ERROR;
1195
1196    // Input parameters check
1197    VIDEOEDITOR_CHECK(M4OSA_NULL != pFormat,           M4ERR_PARAMETER);
1198    VIDEOEDITOR_CHECK(M4OSA_NULL != pEncoderInterface, M4ERR_PARAMETER);
1199
1200    LOGV("VideoEditorVideoEncoder_getInterface begin 0x%x 0x%x %d", pFormat,
1201        pEncoderInterface, mode);
1202
1203    SAFE_MALLOC(*pEncoderInterface, M4ENCODER_GlobalInterface, 1,
1204        "VideoEditorVideoEncoder");
1205
1206    *pFormat = format;
1207
1208    switch( format ) {
1209        case M4ENCODER_kH263:
1210            {
1211                (*pEncoderInterface)->pFctInit =
1212                    VideoEditorVideoEncoder_init_H263;
1213                break;
1214            }
1215        case M4ENCODER_kMPEG4:
1216            {
1217                (*pEncoderInterface)->pFctInit =
1218                    VideoEditorVideoEncoder_init_MPEG4;
1219                break;
1220            }
1221        case M4ENCODER_kH264:
1222            {
1223                (*pEncoderInterface)->pFctInit =
1224                    VideoEditorVideoEncoder_init_H264;
1225                break;
1226            }
1227        default:
1228            LOGV("VideoEditorVideoEncoder_getInterface : unsupported format %d",
1229                format);
1230            VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_PARAMETER);
1231        break;
1232    }
1233    (*pEncoderInterface)->pFctOpen         = VideoEditorVideoEncoder_open;
1234    (*pEncoderInterface)->pFctStart        = VideoEditorVideoEncoder_start;
1235    (*pEncoderInterface)->pFctStop         = VideoEditorVideoEncoder_stop;
1236    (*pEncoderInterface)->pFctPause        = M4OSA_NULL;
1237    (*pEncoderInterface)->pFctResume       = M4OSA_NULL;
1238    (*pEncoderInterface)->pFctClose        = VideoEditorVideoEncoder_close;
1239    (*pEncoderInterface)->pFctCleanup      = VideoEditorVideoEncoder_cleanup;
1240    (*pEncoderInterface)->pFctRegulBitRate =
1241        VideoEditorVideoEncoder_regulBitRate;
1242    (*pEncoderInterface)->pFctEncode       = VideoEditorVideoEncoder_encode;
1243    (*pEncoderInterface)->pFctSetOption    = VideoEditorVideoEncoder_setOption;
1244    (*pEncoderInterface)->pFctGetOption    = VideoEditorVideoEncoder_getOption;
1245
1246cleanUp:
1247    if( M4NO_ERROR == err ) {
1248        LOGV("VideoEditorVideoEncoder_getInterface no error");
1249    } else {
1250        *pEncoderInterface = M4OSA_NULL;
1251        LOGV("VideoEditorVideoEncoder_getInterface ERROR 0x%X", err);
1252    }
1253    return err;
1254}
1255
1256extern "C" {
1257
1258M4OSA_ERR VideoEditorVideoEncoder_getInterface_H263(M4ENCODER_Format* pFormat,
1259        M4ENCODER_GlobalInterface** pEncoderInterface, M4ENCODER_OpenMode mode){
1260    return VideoEditorVideoEncoder_getInterface(M4ENCODER_kH263, pFormat,
1261            pEncoderInterface, mode);
1262}
1263
1264M4OSA_ERR VideoEditorVideoEncoder_getInterface_MPEG4(M4ENCODER_Format* pFormat,
1265        M4ENCODER_GlobalInterface** pEncoderInterface, M4ENCODER_OpenMode mode){
1266    return VideoEditorVideoEncoder_getInterface(M4ENCODER_kMPEG4, pFormat,
1267           pEncoderInterface, mode);
1268}
1269
1270M4OSA_ERR VideoEditorVideoEncoder_getInterface_H264(M4ENCODER_Format* pFormat,
1271        M4ENCODER_GlobalInterface** pEncoderInterface, M4ENCODER_OpenMode mode){
1272    return VideoEditorVideoEncoder_getInterface(M4ENCODER_kH264, pFormat,
1273           pEncoderInterface, mode);
1274
1275}
1276
1277}  // extern "C"
1278
1279}  // namespace android
1280