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