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