• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ------------------------------------------------------------------
2  * Copyright (C) 1998-2009 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 #include "mpeg4_enc.h"
20 #include "oscl_mem.h"
21 
22 #define MAX_SUPPORTED_LAYER 1
23 
24 const uint8 DEFAULT_VOL_HEADER[DEFAULT_VOL_HEADER_LENGTH] =
25 {
26     0x00, 0x00, 0x01, 0xB0, 0x08, 0x00, 0x00, 0x01,
27     0xB5, 0x09, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
28     0x01, 0x20, 0x00, 0x84, 0x40, 0xFA, 0x28, 0x2C,
29     0x20, 0x90, 0xA2, 0x1F
30 };
31 
32 
33 
Mpeg4Encoder_OMX()34 Mpeg4Encoder_OMX::Mpeg4Encoder_OMX()
35 {
36     iVolHeaderFlag = OMX_FALSE;
37 
38     iInitialized = OMX_FALSE;
39     iYUVIn = NULL;
40     ccRGBtoYUV = NULL;
41 
42     // Create a default VOL header
43     oscl_memset(iVolHeader, 0, DEFAULT_VOL_HEADER_LENGTH);
44     oscl_memcpy(iVolHeader, (OsclAny*)DEFAULT_VOL_HEADER, DEFAULT_VOL_HEADER_LENGTH);
45     iVolHeaderSize = DEFAULT_VOL_HEADER_LENGTH;
46 
47     // DV: first check whether compiler supports 64 bits
48     OMX_TICKS test_var = 0x80000000;
49 
50     iSupport64bitTimestamp = false;
51 
52     if (((test_var << 1) >> 1) == test_var)
53     {
54         iSupport64bitTimestamp = true;
55     }
56 
57 }
58 
59 
60 /* Initialization routine */
Mp4EncInit(OMX_S32 iEncMode,OMX_VIDEO_PORTDEFINITIONTYPE aInputParam,OMX_CONFIG_ROTATIONTYPE aInputOrientationType,OMX_VIDEO_PORTDEFINITIONTYPE aEncodeParam,OMX_VIDEO_PARAM_MPEG4TYPE aEncodeMpeg4Param,OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE aErrorCorrection,OMX_VIDEO_PARAM_BITRATETYPE aRateControlType,OMX_VIDEO_PARAM_QUANTIZATIONTYPE aQuantType,OMX_VIDEO_PARAM_MOTIONVECTORTYPE aSearchRange,OMX_VIDEO_PARAM_INTRAREFRESHTYPE aIntraRefresh,OMX_VIDEO_PARAM_H263TYPE aH263Type,OMX_VIDEO_PARAM_PROFILELEVELTYPE * aProfileLevel)61 OMX_ERRORTYPE Mpeg4Encoder_OMX::Mp4EncInit(OMX_S32 iEncMode,
62         OMX_VIDEO_PORTDEFINITIONTYPE aInputParam,
63         OMX_CONFIG_ROTATIONTYPE aInputOrientationType,
64         OMX_VIDEO_PORTDEFINITIONTYPE aEncodeParam,
65         OMX_VIDEO_PARAM_MPEG4TYPE aEncodeMpeg4Param,
66         OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE aErrorCorrection,
67         OMX_VIDEO_PARAM_BITRATETYPE aRateControlType,
68         OMX_VIDEO_PARAM_QUANTIZATIONTYPE aQuantType,
69         OMX_VIDEO_PARAM_MOTIONVECTORTYPE aSearchRange,
70         OMX_VIDEO_PARAM_INTRAREFRESHTYPE aIntraRefresh,
71         OMX_VIDEO_PARAM_H263TYPE aH263Type,
72         OMX_VIDEO_PARAM_PROFILELEVELTYPE* aProfileLevel)
73 {
74     OMX_U8* pMemBuffer;
75     VideoEncOptions aEncOption; /* encoding options */
76 
77     Int quantType[2] = {0, 0};      /* default H.263 quant*/
78 
79     oscl_memset((void*) &iEncoderControl, 0, sizeof(VideoEncControls));
80 
81     switch (iEncMode)
82     {
83         case MODE_H263:
84         {
85             if (aH263Type.nGOBHeaderInterval > 0)
86             {
87                 ENC_Mode = H263_MODE_WITH_ERR_RES;
88             }
89             else
90             {
91                 ENC_Mode = H263_MODE;
92             }
93         }
94         break;
95 
96         case MODE_MPEG4:
97         {
98             if (OMX_TRUE == aEncodeMpeg4Param.bSVH)
99             {
100                 if (aH263Type.nGOBHeaderInterval > 0)
101                 {
102                     ENC_Mode = SHORT_HEADER_WITH_ERR_RES;
103                 }
104                 else
105                 {
106                     ENC_Mode = SHORT_HEADER;
107                 }
108             }
109             else
110             {
111                 if (OMX_TRUE == aErrorCorrection.bEnableDataPartitioning)
112                 {
113                     ENC_Mode = DATA_PARTITIONING_MODE;
114                 }
115                 else if (OMX_TRUE == aErrorCorrection.bEnableResync)
116                 {
117                     ENC_Mode = COMBINE_MODE_WITH_ERR_RES;
118                 }
119                 else
120                 {
121                     ENC_Mode = COMBINE_MODE_NO_ERR_RES;
122                 }
123             }
124         }
125         break;
126 
127         default:
128         {
129             return OMX_ErrorUnsupportedSetting;
130         }
131     }
132 
133     iSrcWidth = aInputParam.nFrameWidth;
134     iSrcHeight = aInputParam.nFrameHeight;
135     iSrcFrameRate = aInputParam.xFramerate;
136 
137     iFrameOrientation = aInputOrientationType.nRotation;
138 
139 
140     if ((OMX_COLOR_FormatYUV420Planar == aInputParam.eColorFormat) ||
141             (OMX_COLOR_Format24bitRGB888 == aInputParam.eColorFormat) ||
142             (OMX_COLOR_Format12bitRGB444 == aInputParam.eColorFormat) ||
143             (OMX_COLOR_FormatYUV420SemiPlanar == aInputParam.eColorFormat))
144     {
145         iVideoFormat = aInputParam.eColorFormat;
146     }
147     else
148     {
149         return OMX_ErrorUnsupportedSetting;
150     }
151 
152     //Verify the input compression format
153     if (OMX_VIDEO_CodingUnused != aInputParam.eCompressionFormat)
154     {
155         //Input port must have no compression supported
156         return OMX_ErrorUnsupportedSetting;
157     }
158 
159 
160     if (OMX_TRUE == iInitialized)
161     {
162         /* clean up before re-initialized */
163         PVCleanUpVideoEncoder(&iEncoderControl);
164         if (iYUVIn)
165         {
166             oscl_free(iYUVIn);
167             iYUVIn = NULL;
168         }
169 
170     }
171 
172     // allocate iYUVIn
173     if (((iSrcWidth & 0xF) || (iSrcHeight & 0xF)) || OMX_COLOR_FormatYUV420Planar != iVideoFormat) /* Not multiple of 16 */
174     {
175         iYUVIn = (uint8*) oscl_malloc(((((iSrcWidth + 15) >> 4) * ((iSrcHeight + 15) >> 4)) * 3) << 7);
176         if (NULL == iYUVIn)
177         {
178             return OMX_ErrorInsufficientResources;
179         }
180     }
181 
182     /* Initialize the color conversion */
183     if (OMX_COLOR_Format24bitRGB888 == iVideoFormat)
184     {
185         ccRGBtoYUV = CCRGB24toYUV420::New();
186         ccRGBtoYUV->Init(iSrcWidth, iSrcHeight, iSrcWidth, iSrcWidth, iSrcHeight, ((iSrcWidth + 15) >> 4) << 4, (iFrameOrientation == 180 ? CCBOTTOM_UP : 0));
187     }
188     if (OMX_COLOR_Format12bitRGB444 == iVideoFormat)
189     {
190         ccRGBtoYUV = CCRGB12toYUV420::New();
191         ccRGBtoYUV->Init(iSrcWidth, iSrcHeight, iSrcWidth, iSrcWidth, iSrcHeight, ((iSrcWidth + 15) >> 4) << 4, (iFrameOrientation == 180 ? CCBOTTOM_UP : 0));
192     }
193     if (OMX_COLOR_FormatYUV420SemiPlanar == iVideoFormat)
194     {
195         ccRGBtoYUV = CCYUV420SEMItoYUV420::New();
196         ccRGBtoYUV->Init(iSrcWidth, iSrcHeight, iSrcWidth, iSrcWidth, iSrcHeight, ((iSrcWidth + 15) >> 4) << 4, (iFrameOrientation == 180 ? CCBOTTOM_UP : 0));
197     }
198 
199 
200     PVGetDefaultEncOption(&aEncOption, 0);
201 
202     aEncOption.encWidth[0] = aEncodeParam.nFrameWidth;
203     aEncOption.encHeight[0] = aEncodeParam.nFrameHeight;
204     aEncOption.encFrameRate[0] = (aEncodeParam.xFramerate >> 16) + (OsclFloat)(aEncodeParam.xFramerate & 0xFFFF) / (1 << 16);
205 
206 
207 
208     switch (aRateControlType.eControlRate)
209     {
210         case OMX_Video_ControlRateDisable:
211         {
212             aEncOption.rcType = CONSTANT_Q;
213             aEncOption.vbvDelay = (float)10.0;
214         }
215         break;
216 
217         case OMX_Video_ControlRateConstant:
218         {
219             aEncOption.rcType = CBR_1;
220             aEncOption.vbvDelay = (float)2.0;
221         }
222         break;
223 
224         case OMX_Video_ControlRateVariable:
225         {
226             aEncOption.rcType = VBR_1;
227             aEncOption.vbvDelay = (float)5.0;
228         }
229         break;
230 
231         default:
232             return OMX_ErrorUnsupportedSetting;
233     }
234 
235     //Set the profile level of encoder
236     switch (aEncodeMpeg4Param.eProfile)
237     {
238         case OMX_VIDEO_MPEG4ProfileSimple:
239         {
240             if (OMX_VIDEO_MPEG4Level0 == aEncodeMpeg4Param.eLevel)
241             {
242                 aEncOption.profile_level = SIMPLE_PROFILE_LEVEL0;
243             }
244             else if (OMX_VIDEO_MPEG4Level1 == aEncodeMpeg4Param.eLevel)
245             {
246                 aEncOption.profile_level = SIMPLE_PROFILE_LEVEL1;
247             }
248             else if (OMX_VIDEO_MPEG4Level2 == aEncodeMpeg4Param.eLevel)
249             {
250                 aEncOption.profile_level = SIMPLE_PROFILE_LEVEL2;
251             }
252             else if (OMX_VIDEO_MPEG4Level3 == aEncodeMpeg4Param.eLevel)
253             {
254                 aEncOption.profile_level = SIMPLE_PROFILE_LEVEL3;
255             }
256             else
257             {
258                 return OMX_ErrorUnsupportedSetting;
259             }
260         }
261         break;
262 
263         case OMX_VIDEO_MPEG4ProfileSimpleScalable:
264         {
265             if (OMX_VIDEO_MPEG4Level0 == aEncodeMpeg4Param.eLevel)
266             {
267                 aEncOption.profile_level = SIMPLE_SCALABLE_PROFILE_LEVEL0;
268             }
269             else if (OMX_VIDEO_MPEG4Level1 == aEncodeMpeg4Param.eLevel)
270             {
271                 aEncOption.profile_level = SIMPLE_SCALABLE_PROFILE_LEVEL1;
272             }
273             else if (OMX_VIDEO_MPEG4Level2 == aEncodeMpeg4Param.eLevel)
274             {
275                 aEncOption.profile_level = SIMPLE_SCALABLE_PROFILE_LEVEL2;
276             }
277             else
278             {
279                 return OMX_ErrorUnsupportedSetting;
280             }
281         }
282         break;
283 
284         case OMX_VIDEO_MPEG4ProfileCore:
285         {
286             if (OMX_VIDEO_MPEG4Level1 == aEncodeMpeg4Param.eLevel)
287             {
288                 aEncOption.profile_level = CORE_PROFILE_LEVEL1;
289             }
290             else if (OMX_VIDEO_MPEG4Level2 == aEncodeMpeg4Param.eLevel)
291             {
292                 aEncOption.profile_level = CORE_PROFILE_LEVEL2;
293             }
294             else
295             {
296                 return OMX_ErrorUnsupportedSetting;
297             }
298         }
299         break;
300 
301         case OMX_VIDEO_MPEG4ProfileCoreScalable:
302         {
303             if (OMX_VIDEO_MPEG4Level1 == aEncodeMpeg4Param.eLevel)
304             {
305                 aEncOption.profile_level = CORE_SCALABLE_PROFILE_LEVEL1;
306             }
307             else if (OMX_VIDEO_MPEG4Level2 == aEncodeMpeg4Param.eLevel)
308             {
309                 aEncOption.profile_level = CORE_SCALABLE_PROFILE_LEVEL2;
310             }
311             else if (OMX_VIDEO_MPEG4Level3 == aEncodeMpeg4Param.eLevel)
312             {
313                 aEncOption.profile_level = CORE_SCALABLE_PROFILE_LEVEL3;
314             }
315             else
316             {
317                 return OMX_ErrorUnsupportedSetting;
318             }
319         }
320         break;
321 
322         default:
323         {
324             return OMX_ErrorUnsupportedSetting;
325         }
326 
327     }
328 
329     aEncOption.encMode = ENC_Mode;
330 
331     if (DATA_PARTITIONING_MODE == ENC_Mode)
332     {
333         aEncOption.packetSize = aEncodeMpeg4Param.nMaxPacketSize;
334     }
335     else
336     {
337         aEncOption.packetSize = aErrorCorrection.nResynchMarkerSpacing / 8;
338     }
339 
340     if ((OMX_TRUE == aErrorCorrection.bEnableRVLC) ||
341             (OMX_TRUE == aEncodeMpeg4Param.bReversibleVLC))
342     {
343         aEncOption.rvlcEnable = PV_ON;
344     }
345     else
346     {
347         aEncOption.rvlcEnable = PV_OFF;
348     }
349 
350     aEncOption.numLayers = MAX_SUPPORTED_LAYER;
351     if ((aEncodeMpeg4Param.nTimeIncRes << 16) > iSrcFrameRate)
352     {
353         aEncOption.timeIncRes = aEncodeMpeg4Param.nTimeIncRes;
354     }
355     else
356     {
357         //Default value
358         aEncOption.timeIncRes = 1000;
359     }
360 
361     if (iSrcFrameRate > 0)
362     {
363         aEncOption.tickPerSrc = (aEncOption.timeIncRes << 16) / iSrcFrameRate;
364     }
365 
366     aEncOption.bitRate[0] = aEncodeParam.nBitrate;
367     aEncOption.iQuant[0] = aQuantType.nQpI;
368     aEncOption.pQuant[0] = aQuantType.nQpP;
369     aEncOption.quantType[0] = quantType[0]; /* default to H.263 */
370 
371 
372     aEncOption.noFrameSkipped = PV_OFF;
373 
374     //IPPPPPPPPPP, indicates I-frame followed by all P-frames
375     if (0xFFFFFFFF == aEncodeMpeg4Param.nPFrames)
376     {
377         aEncOption.intraPeriod = -1;
378     }
379     else
380     {
381         aEncOption.intraPeriod = aEncodeMpeg4Param.nPFrames + 1;
382     }
383 
384     //No support for B Frames
385     if (aEncodeMpeg4Param.nBFrames > 0)
386     {
387         return OMX_ErrorUnsupportedSetting;
388     }
389 
390     //Encoder support only I and P frames picture type
391     if (0 == (aEncodeMpeg4Param.nAllowedPictureTypes &
392               (OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP)))
393     {
394         return OMX_ErrorUnsupportedSetting;
395     }
396 
397     if (OMX_VIDEO_PictureTypeI == aEncodeMpeg4Param.nAllowedPictureTypes) // I-only
398     {
399         aEncOption.intraPeriod = 1;
400     }
401 
402 
403     if ((OMX_VIDEO_IntraRefreshCyclic == aIntraRefresh.eRefreshMode) ||
404             (OMX_VIDEO_IntraRefreshBoth == aIntraRefresh.eRefreshMode))
405     {
406         aEncOption.numIntraMB = aIntraRefresh.nCirMBs;
407     }
408 
409     if ((OMX_VIDEO_IntraRefreshAdaptive == aIntraRefresh.eRefreshMode) ||
410             (OMX_VIDEO_IntraRefreshBoth == aIntraRefresh.eRefreshMode))
411     {
412         aEncOption.sceneDetect = PV_ON;
413     }
414     else
415     {
416         aEncOption.sceneDetect = PV_OFF;
417     }
418 
419     aEncOption.searchRange = (aSearchRange.sXSearchRange <= aSearchRange.sYSearchRange ? aSearchRange.sXSearchRange : aSearchRange.sYSearchRange);
420     aEncOption.mv8x8Enable = PV_OFF; //disable for now(aSearchRange.bFourMV == OMX_TRUE) ? PV_ON : PV_OFF;
421 
422     aEncOption.gobHeaderInterval = aH263Type.nGOBHeaderInterval;
423 
424     aEncOption.useACPred = ((aEncodeMpeg4Param.bACPred == OMX_TRUE) ? PV_ON : PV_OFF);
425 
426     aEncOption.intraDCVlcTh = aEncodeMpeg4Param.nIDCVLCThreshold;
427     /* note aEncOption.intraDCVlcTh will be clipped btw (0,7) inside PV M4V encoder */
428 
429     //Checking the range of parameters that the encoder can't support here
430     // and return OMX_ErrorUnsupportedSetting
431 
432     /***** Initlaize the encoder *****/
433     if (PV_FALSE == PVInitVideoEncoder(&iEncoderControl, &aEncOption))
434     {
435         iInitialized = OMX_FALSE;
436         return OMX_ErrorBadParameter;
437     }
438 
439     iInitialized = OMX_TRUE;
440     iNextModTime = 0;
441 
442 
443     //Update the vol header for non-h263 modes
444     if ((DATA_PARTITIONING_MODE == ENC_Mode) ||
445             (COMBINE_MODE_WITH_ERR_RES == ENC_Mode) ||
446             (COMBINE_MODE_NO_ERR_RES == ENC_Mode) ||
447             (SHORT_HEADER == ENC_Mode) ||
448             (SHORT_HEADER_WITH_ERR_RES == ENC_Mode))
449     {
450         // M4V output, get VOL header
451         iVolHeaderSize = 32; // Encoder requires that buffer size is greater than vol header size (28)
452 
453         pMemBuffer = (OMX_U8*) oscl_malloc(iVolHeaderSize);
454         oscl_memset(pMemBuffer, 0, iVolHeaderSize);
455 
456         int32 Length = iVolHeaderSize;
457 
458         if (PV_FALSE == PVGetVolHeader(&iEncoderControl, (uint8*)pMemBuffer, &Length, 0))
459         {
460             return OMX_ErrorBadParameter;
461         }
462 
463         iVolHeaderSize = Length;
464         oscl_memcpy(iVolHeader, (OsclAny*)pMemBuffer, iVolHeaderSize);
465 
466         oscl_free(pMemBuffer);
467         pMemBuffer = NULL;
468     }
469 
470 
471     //Updating the profile and level from the encoder after initialization
472     if (MODE_MPEG4 == iEncMode)
473     {
474         ProfileLevelType EncProfileLevel;
475         Int temp;
476 
477         if (PV_FALSE == PVGetMPEG4ProfileLevelID(&iEncoderControl, &temp, 0))
478         {
479             return OMX_ErrorBadParameter;
480         }
481         EncProfileLevel = (ProfileLevelType) temp;
482 
483         //Convert the EncProfileLevel to appropriate profile and level of openmax
484         if (SIMPLE_PROFILE_LEVEL0 == EncProfileLevel)
485         {
486             aProfileLevel->eProfile = OMX_VIDEO_MPEG4ProfileSimple;
487             aProfileLevel->eLevel = OMX_VIDEO_MPEG4Level0;
488 
489         }
490         else if (SIMPLE_PROFILE_LEVEL1 == EncProfileLevel)
491         {
492             aProfileLevel->eProfile = OMX_VIDEO_MPEG4ProfileSimple;
493             aProfileLevel->eLevel = OMX_VIDEO_MPEG4Level1;
494         }
495         else if (SIMPLE_PROFILE_LEVEL2 == EncProfileLevel)
496         {
497             aProfileLevel->eProfile = OMX_VIDEO_MPEG4ProfileSimple;
498             aProfileLevel->eLevel = OMX_VIDEO_MPEG4Level2;
499         }
500         else if (SIMPLE_PROFILE_LEVEL3 == EncProfileLevel)
501         {
502             aProfileLevel->eProfile = OMX_VIDEO_MPEG4ProfileSimple;
503             aProfileLevel->eLevel = OMX_VIDEO_MPEG4Level3;
504         }
505         else if (CORE_PROFILE_LEVEL1 == EncProfileLevel)
506         {
507             aProfileLevel->eProfile = OMX_VIDEO_MPEG4ProfileCore;
508             aProfileLevel->eLevel = OMX_VIDEO_MPEG4Level1;
509         }
510         else if (CORE_PROFILE_LEVEL2 == EncProfileLevel)
511         {
512             aProfileLevel->eProfile = OMX_VIDEO_MPEG4ProfileCore;
513             aProfileLevel->eLevel = OMX_VIDEO_MPEG4Level2;
514         }
515         else if (SIMPLE_SCALABLE_PROFILE_LEVEL0 == EncProfileLevel)
516         {
517             aProfileLevel->eProfile = OMX_VIDEO_MPEG4ProfileSimpleScalable;
518             aProfileLevel->eLevel = OMX_VIDEO_MPEG4Level0;
519         }
520         else if (SIMPLE_SCALABLE_PROFILE_LEVEL1 == EncProfileLevel)
521         {
522             aProfileLevel->eProfile = OMX_VIDEO_MPEG4ProfileSimpleScalable;
523             aProfileLevel->eLevel = OMX_VIDEO_MPEG4Level1;
524         }
525         else if (SIMPLE_SCALABLE_PROFILE_LEVEL2 == EncProfileLevel)
526         {
527             aProfileLevel->eProfile = OMX_VIDEO_MPEG4ProfileSimpleScalable;
528             aProfileLevel->eLevel = OMX_VIDEO_MPEG4Level2;
529         }
530         else if (CORE_SCALABLE_PROFILE_LEVEL1 == EncProfileLevel)
531         {
532             aProfileLevel->eProfile = OMX_VIDEO_MPEG4ProfileCoreScalable;
533             aProfileLevel->eLevel = OMX_VIDEO_MPEG4Level1;
534         }
535         else if (CORE_SCALABLE_PROFILE_LEVEL2 == EncProfileLevel)
536         {
537             aProfileLevel->eProfile = OMX_VIDEO_MPEG4ProfileCoreScalable;
538             aProfileLevel->eLevel = OMX_VIDEO_MPEG4Level2;
539         }
540         else if (CORE_SCALABLE_PROFILE_LEVEL3 == EncProfileLevel)
541         {
542             aProfileLevel->eProfile = OMX_VIDEO_MPEG4ProfileCoreScalable;
543             aProfileLevel->eLevel = OMX_VIDEO_MPEG4Level3;
544         }
545         else
546         {
547             //None of the supported parameter found
548             return OMX_ErrorBadParameter;
549         }
550     }
551     //mode H263
552     else
553     {
554         Int ProfileID, LevelID;
555 
556         if (PV_FALSE == PVGetH263ProfileLevelID(&iEncoderControl, &ProfileID, &LevelID))
557         {
558             return OMX_ErrorBadParameter;
559         }
560 
561         //Converting the encoder level into the openmax parameters
562         //Profile is set constant at baseline
563         if (10 == LevelID)
564         {
565             aProfileLevel->eLevel = OMX_VIDEO_H263Level10;
566         }
567         else if (20 == LevelID)
568         {
569             aProfileLevel->eLevel = OMX_VIDEO_H263Level20;
570         }
571         else if (30 == LevelID)
572         {
573             aProfileLevel->eLevel = OMX_VIDEO_H263Level30;
574         }
575         else if (40 == LevelID)
576         {
577             aProfileLevel->eLevel = OMX_VIDEO_H263Level40;
578         }
579         else if (50 == LevelID)
580         {
581             aProfileLevel->eLevel = OMX_VIDEO_H263Level50;
582         }
583         else if (60 == LevelID)
584         {
585             aProfileLevel->eLevel = OMX_VIDEO_H263Level60;
586         }
587         else if (70 == LevelID)
588         {
589             aProfileLevel->eLevel = OMX_VIDEO_H263Level70;
590         }
591         else
592         {
593             //None of the supported parameter found
594             return OMX_ErrorBadParameter;
595         }
596     }
597 
598     return OMX_ErrorNone;
599 
600 }
601 
602 
Mp4RequestIFrame()603 OMX_ERRORTYPE Mpeg4Encoder_OMX::Mp4RequestIFrame()
604 {
605     if (PV_TRUE != PVIFrameRequest(&iEncoderControl))
606     {
607         return OMX_ErrorUndefined;
608     }
609 
610     return OMX_ErrorNone;
611 }
612 
613 
Mp4UpdateBitRate(OMX_U32 aEncodedBitRate)614 OMX_BOOL Mpeg4Encoder_OMX::Mp4UpdateBitRate(OMX_U32 aEncodedBitRate)
615 {
616     Int BitRate[2] = {0, 0};
617     OMX_BOOL Status = OMX_TRUE;
618 
619     //Update the bit rate only if encoder has been initialized
620     if (OMX_TRUE == iInitialized)
621     {
622         BitRate[0] = aEncodedBitRate;
623 
624         Status = (OMX_BOOL) PVUpdateBitRate(&iEncoderControl, BitRate);
625     }
626     return Status;
627 }
628 
629 
Mp4UpdateFrameRate(OMX_U32 aEncodeFramerate)630 OMX_BOOL Mpeg4Encoder_OMX::Mp4UpdateFrameRate(OMX_U32 aEncodeFramerate)
631 {
632     float EncFrameRate[2] = {0., 0.};
633     OMX_BOOL Status = OMX_TRUE;
634 
635     //Update the frame rate only if encoder has been initialized
636     if (OMX_TRUE == iInitialized)
637     {
638         EncFrameRate[0] = (float)(aEncodeFramerate >> 16);
639         Status = (OMX_BOOL) PVUpdateEncFrameRate(&iEncoderControl, EncFrameRate);
640     }
641     return Status;
642 
643 }
644 
645 
646 
647 
648 /*Encode routine */
Mp4EncodeVideo(OMX_U8 * aOutBuffer,OMX_U32 * aOutputLength,OMX_BOOL * aBufferOverRun,OMX_U8 ** aOverBufferPointer,OMX_U8 * aInBuffer,OMX_U32 aInBufSize,OMX_TICKS aInTimeStamp,OMX_TICKS * aOutTimeStamp,OMX_BOOL * aSyncFlag)649 OMX_BOOL Mpeg4Encoder_OMX::Mp4EncodeVideo(OMX_U8*    aOutBuffer,
650         OMX_U32*   aOutputLength,
651         OMX_BOOL*  aBufferOverRun,
652         OMX_U8**   aOverBufferPointer,
653         OMX_U8*    aInBuffer,
654         OMX_U32    aInBufSize,
655         OMX_TICKS  aInTimeStamp,
656         OMX_TICKS* aOutTimeStamp,
657         OMX_BOOL*  aSyncFlag)
658 {
659     *aSyncFlag = OMX_FALSE;
660 
661     if (OMX_FALSE == iVolHeaderFlag)
662     {
663         iVolHeaderFlag = OMX_TRUE;
664         iNextModTime = aInTimeStamp;
665 
666         //Send the first output buffer as vol header in case of m4v format
667         if ((DATA_PARTITIONING_MODE == ENC_Mode) ||
668                 (COMBINE_MODE_WITH_ERR_RES == ENC_Mode) ||
669                 (COMBINE_MODE_NO_ERR_RES == ENC_Mode) ||
670                 (SHORT_HEADER == ENC_Mode) ||
671                 (SHORT_HEADER_WITH_ERR_RES == ENC_Mode))
672         {
673             oscl_memcpy(aOutBuffer, iVolHeader, iVolHeaderSize);
674             *aOutputLength = iVolHeaderSize;
675             *aOutTimeStamp = aInTimeStamp;
676             return OMX_TRUE;
677         }
678     }
679 
680 
681     /* Input Buffer Size Check
682      * Input buffer size should be equal to one frame, otherwise drop the frame
683      * as it is a corrupt data and don't encode it */
684 
685     if (OMX_COLOR_FormatYUV420Planar == iVideoFormat)
686     {
687         if (aInBufSize < (OMX_U32)((iSrcWidth * iSrcHeight * 3) >> 1))
688         {
689             *aOutputLength = 0;
690             return OMX_FALSE;
691         }
692     }
693     else if (OMX_COLOR_Format24bitRGB888 == iVideoFormat)
694     {
695         if (aInBufSize < (OMX_U32)(iSrcWidth * iSrcHeight * 3))
696         {
697             *aOutputLength = 0;
698             return OMX_FALSE;
699         }
700     }
701     else if (OMX_COLOR_Format12bitRGB444 == iVideoFormat)
702     {
703         if (aInBufSize < (OMX_U32)(iSrcWidth * iSrcHeight * 2))
704         {
705             *aOutputLength = 0;
706             return OMX_FALSE;
707         }
708     }
709     else if (OMX_COLOR_FormatYUV420SemiPlanar == iVideoFormat)
710     {
711         if (aInBufSize < (OMX_U32)((iSrcWidth * iSrcHeight * 3) >> 1))
712         {
713             *aOutputLength = 0;
714             return OMX_FALSE;
715         }
716     }
717 
718     //Now encode the input buffer
719     VideoEncFrameIO vid_in, vid_out;
720     Int Size;
721     Bool status;
722     ULong modTime;
723     Int nLayer = 0;
724     uint32 UpperTimeStamp = 0;
725 
726 
727 
728     if (iSupport64bitTimestamp)
729     {
730         //Considering the difference in data types of aInTimeStamp and iNextModTime
731         OMX_U64 temp = 0x00000000FFFFFFFF;
732 
733         UpperTimeStamp = (aInTimeStamp & (temp << 32)) >> 32;
734         if (UpperTimeStamp > 0)
735         {
736             //The data is more than 32 bits, save the upper 32 bits to be copied later in the output timestamp
737             aInTimeStamp = aInTimeStamp & 0x00000000FFFFFFFF;
738         }
739     }
740     // else, timestamp just remains what it is
741 
742     // Time to encode if aInTimeStamp >= iNextModTime */
743     uint32 temp = (uint32)aInTimeStamp; /* for type-punned reference warning in the next line*/
744     if (OMX_TRUE == LessThan(iNextModTime, (uint32&)temp, PVMFTIMESTAMP_LESSTHAN_THRESHOLD))
745     {
746         Size = *aOutputLength;
747 
748         if (iVideoFormat == OMX_COLOR_FormatYUV420Planar)
749         {
750             if (iYUVIn) /* iSrcWidth or iSrcHeight is not multiple of 16 */
751             {
752                 CopyToYUVIn(aInBuffer, iSrcWidth, iSrcHeight,
753                             ((iSrcWidth + 15) >> 4) << 4, ((iSrcHeight + 15) >> 4) << 4);
754                 iVideoIn = iYUVIn;
755             }
756             else /* otherwise, we can just use aVidIn->iSource */
757             {
758                 iVideoIn = aInBuffer;
759             }
760         }
761 
762         else if ((iVideoFormat == OMX_COLOR_Format12bitRGB444) || (iVideoFormat == OMX_COLOR_Format24bitRGB888) || (iVideoFormat == OMX_COLOR_FormatYUV420SemiPlanar))
763         {
764             ccRGBtoYUV->Convert((uint8*)aInBuffer, iYUVIn);
765             iVideoIn = iYUVIn;
766         }
767 
768         /* with backward-P or B-Vop this timestamp must be re-ordered */
769         *aOutTimeStamp = aInTimeStamp;
770 
771         vid_in.height = ((iSrcHeight + 15) >> 4) << 4;
772         vid_in.pitch = ((iSrcWidth + 15) >> 4) << 4;
773         vid_in.timestamp = aInTimeStamp;
774         vid_in.yChan = (UChar*)iVideoIn;
775         vid_in.uChan = (UChar*)(iVideoIn + vid_in.height * vid_in.pitch);
776         vid_in.vChan = vid_in.uChan + ((vid_in.height * vid_in.pitch) >> 2);
777 
778         status = PVEncodeVideoFrame(&iEncoderControl, &vid_in, &vid_out,
779                                     &modTime, (UChar*)aOutBuffer,
780                                     &Size, &nLayer);
781 
782 
783         if (status == PV_TRUE)
784         {
785             iNextModTime = modTime;
786 
787             if ((nLayer >= 0) && ((OMX_U32) Size > *aOutputLength)) // overrun buffer is used by the encoder
788             {
789                 *aOverBufferPointer = PVGetOverrunBuffer(&iEncoderControl);
790                 *aBufferOverRun = OMX_TRUE;
791             }
792 
793             *aOutputLength = Size;
794 
795             if (Size > 0)
796             {
797                 *aOutTimeStamp = vid_out.timestamp;
798 
799                 if (iSupport64bitTimestamp)
800                 {
801                     if (UpperTimeStamp > 0)
802                     {
803                         //Copy the upper 32 bits value back to the output timestamp
804                         OMX_S64 TempValue = UpperTimeStamp;
805                         TempValue = TempValue << 32;
806                         *aOutTimeStamp |= TempValue;
807                     }
808                 }
809 
810                 PVGetHintTrack(&iEncoderControl, &iHintTrack);
811                 if (0 == iHintTrack.CodeType)
812                 {
813                     //Its an I Frame, mark the sync flag as true
814                     *aSyncFlag = OMX_TRUE;
815                 }
816             }
817 
818             return OMX_TRUE;
819         }
820         else
821         {
822             *aOutputLength = 0;
823             return OMX_FALSE;
824         }
825     }
826     else /* if(aInTimeStamp >= iNextModTime) */
827     {
828         *aOutputLength = 0;
829         return OMX_TRUE;
830     }
831 }
832 
833 
834 
Mp4EncDeinit()835 OMX_ERRORTYPE Mpeg4Encoder_OMX::Mp4EncDeinit()
836 {
837     if (OMX_TRUE == iInitialized)
838     {
839         PVCleanUpVideoEncoder(&iEncoderControl);
840         iInitialized = OMX_FALSE;
841 
842         if (iYUVIn)
843         {
844             oscl_free(iYUVIn);
845             iYUVIn = NULL;
846         }
847 
848         if (ccRGBtoYUV)
849         {
850             OSCL_DELETE(ccRGBtoYUV);
851             ccRGBtoYUV = NULL;
852         }
853 
854     }
855     return OMX_ErrorNone;
856 }
857 
858 
859 /* COLOUR CONVERSION ROUTINES ARE WRITTEN BELOW*/
860 
861 /* ///////////////////////////////////////////////////////////////////////// */
862 /* Copy from YUV input to YUV frame inside M4VEnc lib                       */
863 /* When input is not YUV, the color conv will write it directly to iVideoInOut. */
864 /* ///////////////////////////////////////////////////////////////////////// */
865 
CopyToYUVIn(uint8 * YUV,Int width,Int height,Int width_16,Int height_16)866 void Mpeg4Encoder_OMX::CopyToYUVIn(uint8 *YUV, Int width, Int height, Int width_16, Int height_16)
867 {
868     UChar *y, *u, *v, *yChan, *uChan, *vChan;
869     Int y_ind, ilimit, jlimit, i, j, ioffset;
870     Int size = width * height;
871     Int size16 = width_16 * height_16;
872 
873     /* do padding at the bottom first */
874     /* do padding if input RGB size(height) is different from the output YUV size(height_16) */
875     if (height < height_16 || width < width_16) /* if padding */
876     {
877         Int offset = (height < height_16) ? height : height_16;
878 
879         offset = (offset * width_16);
880 
881         if (width < width_16)
882         {
883             offset -= (width_16 - width);
884         }
885 
886         yChan = (UChar*)(iYUVIn + offset);
887         oscl_memset(yChan, 16, size16 - offset); /* pad with zeros */
888 
889         uChan = (UChar*)(iYUVIn + size16 + (offset >> 2));
890         oscl_memset(uChan, 128, (size16 - offset) >> 2);
891 
892         vChan = (UChar*)(iYUVIn + size16 + (size16 >> 2) + (offset >> 2));
893         oscl_memset(vChan, 128, (size16 - offset) >> 2);
894     }
895 
896     /* then do padding on the top */
897     yChan = (UChar*)iYUVIn; /* Normal order */
898     uChan = (UChar*)(iYUVIn + size16);
899     vChan = (UChar*)(uChan + (size16 >> 2));
900 
901     u = (UChar*)(&(YUV[size]));
902     v = (UChar*)(&(YUV[size*5/4]));
903 
904     /* To center the output */
905     if (height_16 > height)
906     {  /* output taller than input */
907         if (width_16 >= width)
908         { /* output wider than or equal input */
909             i = ((height_16 - height) >> 1) * width_16 + (((width_16 - width) >> 3) << 2);
910             /* make sure that (width_16-width)>>1 is divisible by 4 */
911             j = ((height_16 - height) >> 2) * (width_16 >> 1) + (((width_16 - width) >> 4) << 2);
912             /* make sure that (width_16-width)>>2 is divisible by 4 */
913         }
914         else
915         { /* output narrower than input */
916             i = ((height_16 - height) >> 1) * width_16;
917             j = ((height_16 - height) >> 2) * (width_16 >> 1);
918             YUV += ((width - width_16) >> 1);
919             u += ((width - width_16) >> 2);
920             v += ((width - width_16) >> 2);
921         }
922         oscl_memset((uint8 *)yChan, 16, i);
923         yChan += i;
924         oscl_memset((uint8 *)uChan, 128, j);
925         uChan += j;
926         oscl_memset((uint8 *)vChan, 128, j);
927         vChan += j;
928     }
929     else
930     {  /* output shorter or equal input */
931         if (width_16 >= width)
932         {  /* output wider or equal input */
933             i = (((width_16 - width) >> 3) << 2);
934             /* make sure that (width_16-width)>>1 is divisible by 4 */
935             j = (((width_16 - width) >> 4) << 2);
936             /* make sure that (width_16-width)>>2 is divisible by 4 */
937             YUV += (((height - height_16) >> 1) * width);
938             u += (((height - height_16) >> 1) * width) >> 2;
939             v += (((height - height_16) >> 1) * width) >> 2;
940         }
941         else
942         { /* output narrower than input */
943             i = 0;
944             j = 0;
945             YUV += (((height - height_16) >> 1) * width + ((width - width_16) >> 1));
946             u += (((height - height_16) >> 1) * width + ((width - width_16) >> 1)) >> 2;
947             v += (((height - height_16) >> 1) * width + ((width - width_16) >> 1)) >> 2;
948         }
949         oscl_memset((uint8 *)yChan, 16, i);
950         yChan += i;
951         oscl_memset((uint8 *)uChan, 128, j);
952         uChan += j;
953         oscl_memset((uint8 *)vChan, 128, j);
954         vChan += j;
955     }
956 
957     /* Copy with cropping or zero-padding */
958     if (height < height_16)
959         jlimit = height;
960     else
961         jlimit = height_16;
962 
963     if (width < width_16)
964     {
965         ilimit = width;
966         ioffset = width_16 - width;
967     }
968     else
969     {
970         ilimit = width_16;
971         ioffset = 0;
972     }
973 
974     /* Copy Y */
975     /* Set up pointer for fast looping */
976     y = (UChar*)YUV;
977 
978     if (width == width_16 && height == height_16) /* no need to pad */
979     {
980         oscl_memcpy(yChan, y, size);
981     }
982     else
983     {
984         for (y_ind = 0; y_ind < (jlimit - 1) ; y_ind++)
985         {
986             oscl_memcpy(yChan, y, ilimit);
987             oscl_memset(yChan + ilimit, 16, ioffset); /* pad with zero */
988             yChan += width_16;
989             y += width;
990         }
991         oscl_memcpy(yChan, y, ilimit); /* last line no padding */
992     }
993     /* Copy U and V */
994     /* Set up pointers for fast looping */
995     if (width == width_16 && height == height_16) /* no need to pad */
996     {
997         oscl_memcpy(uChan, u, size >> 2);
998         oscl_memcpy(vChan, v, size >> 2);
999     }
1000     else
1001     {
1002         for (y_ind = 0; y_ind < (jlimit >> 1) - 1; y_ind++)
1003         {
1004             oscl_memcpy(uChan, u, ilimit >> 1);
1005             oscl_memcpy(vChan, v, ilimit >> 1);
1006             oscl_memset(uChan + (ilimit >> 1), 128, ioffset >> 1);
1007             oscl_memset(vChan + (ilimit >> 1), 128, ioffset >> 1);
1008             uChan += (width_16 >> 1);
1009             u += (width >> 1);
1010             vChan += (width_16 >> 1);
1011             v += (width >> 1);
1012         }
1013         oscl_memcpy(uChan, u, ilimit >> 1); /* last line no padding */
1014         oscl_memcpy(vChan, v, ilimit >> 1);
1015     }
1016 
1017     return ;
1018 }
1019 
1020 
1021 /**
1022  * Compares two timestamps and reports if the first occurred before (is less than)
1023  * the second value.
1024  * @param a first timestamp value in the comparison
1025  * @param b second timestamp value in the comparison
1026  * @return true if a < b, false otherwise.
1027  *
1028  */
LessThan(uint32 & a,uint32 & b,uint32 Threshold=PVMFTIMESTAMP_LESSTHAN_THRESHOLD)1029 OMX_BOOL Mpeg4Encoder_OMX::LessThan(uint32& a, uint32& b,
1030                                     uint32 Threshold = PVMFTIMESTAMP_LESSTHAN_THRESHOLD)
1031 {
1032     uint32 c = b;
1033     c -= a;
1034 
1035     if (c < Threshold)
1036     {
1037         return OMX_TRUE;
1038     }
1039 
1040     return OMX_FALSE;
1041 }
1042