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