blob: 9f141ac58e75f6f9f97379d97570f3b1466c281b [file] [log] [blame]
Andreas Huber4b3913a2011-05-11 14:13:42 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "SoftAVC"
19#include <utils/Log.h>
20
21#include "SoftAVC.h"
22
23#include <media/stagefright/foundation/ADebug.h>
24#include <media/stagefright/MediaDefs.h>
25#include <media/stagefright/MediaErrors.h>
26
27#include "avcdec_api.h"
28#include "avcdec_int.h"
29
30namespace android {
31
32static const char kStartCode[4] = { 0x00, 0x00, 0x00, 0x01 };
33
34template<class T>
35static void InitOMXParams(T *params) {
36 params->nSize = sizeof(T);
37 params->nVersion.s.nVersionMajor = 1;
38 params->nVersion.s.nVersionMinor = 0;
39 params->nVersion.s.nRevision = 0;
40 params->nVersion.s.nStep = 0;
41}
42
43static int32_t Malloc(void *userData, int32_t size, int32_t attrs) {
44 return reinterpret_cast<int32_t>(malloc(size));
45}
46
47static void Free(void *userData, int32_t ptr) {
48 free(reinterpret_cast<void *>(ptr));
49}
50
51SoftAVC::SoftAVC(
52 const char *name,
53 const OMX_CALLBACKTYPE *callbacks,
54 OMX_PTR appData,
55 OMX_COMPONENTTYPE **component)
56 : SimpleSoftOMXComponent(name, callbacks, appData, component),
57 mHandle(new tagAVCHandle),
58 mInputBufferCount(0),
59 mWidth(160),
60 mHeight(120),
61 mCropLeft(0),
62 mCropTop(0),
63 mCropRight(mWidth - 1),
64 mCropBottom(mHeight - 1),
65 mSPSSeen(false),
66 mPPSSeen(false),
67 mCurrentTimeUs(-1),
68 mEOSStatus(INPUT_DATA_AVAILABLE),
69 mOutputPortSettingsChange(NONE) {
70 initPorts();
71 CHECK_EQ(initDecoder(), (status_t)OK);
72}
73
74SoftAVC::~SoftAVC() {
75 PVAVCCleanUpDecoder(mHandle);
76
77 delete mHandle;
78 mHandle = NULL;
79}
80
81void SoftAVC::initPorts() {
82 OMX_PARAM_PORTDEFINITIONTYPE def;
83 InitOMXParams(&def);
84
85 def.nPortIndex = 0;
86 def.eDir = OMX_DirInput;
87 def.nBufferCountMin = kNumInputBuffers;
88 def.nBufferCountActual = def.nBufferCountMin;
89 def.nBufferSize = 8192;
90 def.bEnabled = OMX_TRUE;
91 def.bPopulated = OMX_FALSE;
92 def.eDomain = OMX_PortDomainVideo;
93 def.bBuffersContiguous = OMX_FALSE;
94 def.nBufferAlignment = 1;
95
96 def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_AVC);
97 def.format.video.pNativeRender = NULL;
98 def.format.video.nFrameWidth = mWidth;
99 def.format.video.nFrameHeight = mHeight;
100 def.format.video.nStride = def.format.video.nFrameWidth;
101 def.format.video.nSliceHeight = def.format.video.nFrameHeight;
102 def.format.video.nBitrate = 0;
103 def.format.video.xFramerate = 0;
104 def.format.video.bFlagErrorConcealment = OMX_FALSE;
105 def.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
106 def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
107 def.format.video.pNativeWindow = NULL;
108
109 addPort(def);
110
111 def.nPortIndex = 1;
112 def.eDir = OMX_DirOutput;
113 def.nBufferCountMin = kNumOutputBuffers;
114 def.nBufferCountActual = def.nBufferCountMin;
115 def.bEnabled = OMX_TRUE;
116 def.bPopulated = OMX_FALSE;
117 def.eDomain = OMX_PortDomainVideo;
118 def.bBuffersContiguous = OMX_FALSE;
119 def.nBufferAlignment = 2;
120
121 def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
122 def.format.video.pNativeRender = NULL;
123 def.format.video.nFrameWidth = mWidth;
124 def.format.video.nFrameHeight = mHeight;
125 def.format.video.nStride = def.format.video.nFrameWidth;
126 def.format.video.nSliceHeight = def.format.video.nFrameHeight;
127 def.format.video.nBitrate = 0;
128 def.format.video.xFramerate = 0;
129 def.format.video.bFlagErrorConcealment = OMX_FALSE;
130 def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
131 def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
132 def.format.video.pNativeWindow = NULL;
133
134 def.nBufferSize =
135 (def.format.video.nFrameWidth * def.format.video.nFrameHeight * 3) / 2;
136
137 addPort(def);
138}
139
140status_t SoftAVC::initDecoder() {
141 memset(mHandle, 0, sizeof(tagAVCHandle));
142 mHandle->AVCObject = NULL;
143 mHandle->userData = this;
144 mHandle->CBAVC_DPBAlloc = ActivateSPSWrapper;
145 mHandle->CBAVC_FrameBind = BindFrameWrapper;
146 mHandle->CBAVC_FrameUnbind = UnbindFrame;
147 mHandle->CBAVC_Malloc = Malloc;
148 mHandle->CBAVC_Free = Free;
149
150 return OK;
151}
152
153OMX_ERRORTYPE SoftAVC::internalGetParameter(
154 OMX_INDEXTYPE index, OMX_PTR params) {
155 switch (index) {
156 case OMX_IndexParamVideoPortFormat:
157 {
158 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
159 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
160
161 if (formatParams->nPortIndex > 1) {
162 return OMX_ErrorUndefined;
163 }
164
165 if (formatParams->nIndex != 0) {
166 return OMX_ErrorNoMore;
167 }
168
169 if (formatParams->nPortIndex == 0) {
170 formatParams->eCompressionFormat = OMX_VIDEO_CodingAVC;
171 formatParams->eColorFormat = OMX_COLOR_FormatUnused;
172 formatParams->xFramerate = 0;
173 } else {
174 CHECK_EQ(formatParams->nPortIndex, 1u);
175
176 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
177 formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
178 formatParams->xFramerate = 0;
179 }
180
181 return OMX_ErrorNone;
182 }
183
184 default:
185 return SimpleSoftOMXComponent::internalGetParameter(index, params);
186 }
187}
188
189OMX_ERRORTYPE SoftAVC::internalSetParameter(
190 OMX_INDEXTYPE index, const OMX_PTR params) {
191 switch (index) {
192 case OMX_IndexParamStandardComponentRole:
193 {
194 const OMX_PARAM_COMPONENTROLETYPE *roleParams =
195 (const OMX_PARAM_COMPONENTROLETYPE *)params;
196
197 if (strncmp((const char *)roleParams->cRole,
198 "video_decoder.avc",
199 OMX_MAX_STRINGNAME_SIZE - 1)) {
200 return OMX_ErrorUndefined;
201 }
202
203 return OMX_ErrorNone;
204 }
205
206 case OMX_IndexParamVideoPortFormat:
207 {
208 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
209 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
210
211 if (formatParams->nPortIndex > 1) {
212 return OMX_ErrorUndefined;
213 }
214
215 if (formatParams->nIndex != 0) {
216 return OMX_ErrorNoMore;
217 }
218
219 return OMX_ErrorNone;
220 }
221
222 default:
223 return SimpleSoftOMXComponent::internalSetParameter(index, params);
224 }
225}
226
227OMX_ERRORTYPE SoftAVC::getConfig(
228 OMX_INDEXTYPE index, OMX_PTR params) {
229 switch (index) {
230 case OMX_IndexConfigCommonOutputCrop:
231 {
232 OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params;
233
234 if (rectParams->nPortIndex != 1) {
235 return OMX_ErrorUndefined;
236 }
237
238 rectParams->nLeft = mCropLeft;
239 rectParams->nTop = mCropTop;
240 rectParams->nWidth = mCropRight - mCropLeft + 1;
241 rectParams->nHeight = mCropBottom - mCropTop + 1;
242
243 return OMX_ErrorNone;
244 }
245
246 default:
247 return OMX_ErrorUnsupportedIndex;
248 }
249}
250
251static void findNALFragment(
252 const OMX_BUFFERHEADERTYPE *inHeader,
253 const uint8_t **fragPtr, size_t *fragSize) {
254 const uint8_t *data = inHeader->pBuffer + inHeader->nOffset;
255
256 size_t size = inHeader->nFilledLen;
257
258 CHECK(size >= 4);
259 CHECK(!memcmp(kStartCode, data, 4));
260
261 size_t offset = 4;
262 while (offset + 3 < size && memcmp(kStartCode, &data[offset], 4)) {
263 ++offset;
264 }
265
266 *fragPtr = &data[4];
267 if (offset + 3 >= size) {
268 *fragSize = size - 4;
269 } else {
270 *fragSize = offset - 4;
271 }
272}
273
274void SoftAVC::onQueueFilled(OMX_U32 portIndex) {
275 if (mOutputPortSettingsChange != NONE) {
276 return;
277 }
278
279 List<BufferInfo *> &inQueue = getPortQueue(0);
280 List<BufferInfo *> &outQueue = getPortQueue(1);
281
282 if (mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
283 return;
284 }
285
286 while ((mEOSStatus != INPUT_DATA_AVAILABLE || !inQueue.empty())
287 && outQueue.size() == kNumOutputBuffers) {
288 if (mEOSStatus == INPUT_EOS_SEEN) {
289 OMX_BUFFERHEADERTYPE *outHeader;
290 if (drainOutputBuffer(&outHeader)) {
291 List<BufferInfo *>::iterator it = outQueue.begin();
292 while ((*it)->mHeader != outHeader) {
293 ++it;
294 }
295
296 BufferInfo *outInfo = *it;
297 outInfo->mOwnedByUs = false;
298 outQueue.erase(it);
299 outInfo = NULL;
300
301 notifyFillBufferDone(outHeader);
302 outHeader = NULL;
303 return;
304 }
305
306 BufferInfo *outInfo = *outQueue.begin();
307 outHeader = outInfo->mHeader;
308
309 outHeader->nOffset = 0;
310 outHeader->nFilledLen = 0;
311 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
312 outHeader->nTimeStamp = 0;
313
314 outQueue.erase(outQueue.begin());
315 outInfo->mOwnedByUs = false;
316 notifyFillBufferDone(outHeader);
317
318 mEOSStatus = OUTPUT_FRAMES_FLUSHED;
319 return;
320 }
321
322 BufferInfo *inInfo = *inQueue.begin();
323 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
324
325 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
326 inQueue.erase(inQueue.begin());
327 inInfo->mOwnedByUs = false;
328 notifyEmptyBufferDone(inHeader);
329
330 mEOSStatus = INPUT_EOS_SEEN;
331 continue;
332 }
333
334 mCurrentTimeUs = inHeader->nTimeStamp;
335
336 const uint8_t *fragPtr;
337 size_t fragSize;
338 findNALFragment(inHeader, &fragPtr, &fragSize);
339
340 bool releaseFragment;
341 OMX_BUFFERHEADERTYPE *outHeader;
342 status_t err = decodeFragment(
343 fragPtr, fragSize,
344 &releaseFragment, &outHeader);
345
346 if (releaseFragment) {
347 CHECK_GE(inHeader->nFilledLen, fragSize + 4);
348
349 inHeader->nOffset += fragSize + 4;
350 inHeader->nFilledLen -= fragSize + 4;
351
352 if (inHeader->nFilledLen == 0) {
353 inInfo->mOwnedByUs = false;
354 inQueue.erase(inQueue.begin());
355 inInfo = NULL;
356 notifyEmptyBufferDone(inHeader);
357 inHeader = NULL;
358 }
359 }
360
361 if (outHeader != NULL) {
362 List<BufferInfo *>::iterator it = outQueue.begin();
363 while ((*it)->mHeader != outHeader) {
364 ++it;
365 }
366
367 BufferInfo *outInfo = *it;
368 outInfo->mOwnedByUs = false;
369 outQueue.erase(it);
370 outInfo = NULL;
371
372 notifyFillBufferDone(outHeader);
373 outHeader = NULL;
374 return;
375 }
376
377 if (err == INFO_FORMAT_CHANGED) {
378 return;
379 }
380
381 if (err != OK) {
382 notify(OMX_EventError, OMX_ErrorUndefined, err, NULL);
383 return;
384 }
385 }
386}
387
388status_t SoftAVC::decodeFragment(
389 const uint8_t *fragPtr, size_t fragSize,
390 bool *releaseFragment,
391 OMX_BUFFERHEADERTYPE **outHeader) {
392 *releaseFragment = true;
393 *outHeader = NULL;
394
395 int nalType;
396 int nalRefIdc;
397 AVCDec_Status res =
398 PVAVCDecGetNALType(
399 const_cast<uint8_t *>(fragPtr), fragSize,
400 &nalType, &nalRefIdc);
401
402 if (res != AVCDEC_SUCCESS) {
403 LOGV("cannot determine nal type");
404 return ERROR_MALFORMED;
405 }
406
407 if (nalType != AVC_NALTYPE_SPS && nalType != AVC_NALTYPE_PPS
408 && (!mSPSSeen || !mPPSSeen)) {
409 // We haven't seen SPS or PPS yet.
410 return OK;
411 }
412
413 switch (nalType) {
414 case AVC_NALTYPE_SPS:
415 {
416 mSPSSeen = true;
417
418 res = PVAVCDecSeqParamSet(
419 mHandle, const_cast<uint8_t *>(fragPtr),
420 fragSize);
421
422 if (res != AVCDEC_SUCCESS) {
423 return ERROR_MALFORMED;
424 }
425
426 AVCDecObject *pDecVid = (AVCDecObject *)mHandle->AVCObject;
427
428 int32_t width =
429 (pDecVid->seqParams[0]->pic_width_in_mbs_minus1 + 1) * 16;
430
431 int32_t height =
432 (pDecVid->seqParams[0]->pic_height_in_map_units_minus1 + 1) * 16;
433
434 int32_t crop_left, crop_right, crop_top, crop_bottom;
435 if (pDecVid->seqParams[0]->frame_cropping_flag)
436 {
437 crop_left = 2 * pDecVid->seqParams[0]->frame_crop_left_offset;
438 crop_right =
439 width - (2 * pDecVid->seqParams[0]->frame_crop_right_offset + 1);
440
441 if (pDecVid->seqParams[0]->frame_mbs_only_flag)
442 {
443 crop_top = 2 * pDecVid->seqParams[0]->frame_crop_top_offset;
444 crop_bottom =
445 height -
446 (2 * pDecVid->seqParams[0]->frame_crop_bottom_offset + 1);
447 }
448 else
449 {
450 crop_top = 4 * pDecVid->seqParams[0]->frame_crop_top_offset;
451 crop_bottom =
452 height -
453 (4 * pDecVid->seqParams[0]->frame_crop_bottom_offset + 1);
454 }
455 } else {
456 crop_bottom = height - 1;
457 crop_right = width - 1;
458 crop_top = crop_left = 0;
459 }
460
461 status_t err = OK;
462
463 if (mWidth != width || mHeight != height) {
464 mWidth = width;
465 mHeight = height;
466
467 updatePortDefinitions();
468
469 notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
470 mOutputPortSettingsChange = AWAITING_DISABLED;
471
472 err = INFO_FORMAT_CHANGED;
473 }
474
475 if (mCropLeft != crop_left
476 || mCropTop != crop_top
477 || mCropRight != crop_right
478 || mCropBottom != crop_bottom) {
479 mCropLeft = crop_left;
480 mCropTop = crop_top;
481 mCropRight = crop_right;
482 mCropBottom = crop_bottom;
483
484 notify(OMX_EventPortSettingsChanged,
485 1,
486 OMX_IndexConfigCommonOutputCrop,
487 NULL);
488 }
489
490 return err;
491 }
492
493 case AVC_NALTYPE_PPS:
494 {
495 mPPSSeen = true;
496
497 res = PVAVCDecPicParamSet(
498 mHandle, const_cast<uint8_t *>(fragPtr),
499 fragSize);
500
501 if (res != AVCDEC_SUCCESS) {
502 LOGV("PVAVCDecPicParamSet returned error %d", res);
503 return ERROR_MALFORMED;
504 }
505
506 return OK;
507 }
508
509 case AVC_NALTYPE_SLICE:
510 case AVC_NALTYPE_IDR:
511 {
512 res = PVAVCDecodeSlice(
513 mHandle, const_cast<uint8_t *>(fragPtr),
514 fragSize);
515
516 if (res == AVCDEC_PICTURE_OUTPUT_READY) {
517 *releaseFragment = false;
518
519 if (!drainOutputBuffer(outHeader)) {
520 return UNKNOWN_ERROR;
521 }
522
523 return OK;
524 }
525
526 if (res == AVCDEC_PICTURE_READY || res == AVCDEC_SUCCESS) {
527 return OK;
528 } else {
529 LOGV("PVAVCDecodeSlice returned error %d", res);
530 return ERROR_MALFORMED;
531 }
532 }
533
534 case AVC_NALTYPE_SEI:
535 {
536 res = PVAVCDecSEI(
537 mHandle, const_cast<uint8_t *>(fragPtr),
538 fragSize);
539
540 if (res != AVCDEC_SUCCESS) {
541 return ERROR_MALFORMED;
542 }
543
544 return OK;
545 }
546
547 case AVC_NALTYPE_AUD:
548 case AVC_NALTYPE_FILL:
549 case AVC_NALTYPE_EOSEQ:
550 {
551 return OK;
552 }
553
554 default:
555 {
556 LOGE("Should not be here, unknown nalType %d", nalType);
557
558 return ERROR_MALFORMED;
559 }
560 }
561
562 return OK;
563}
564
565bool SoftAVC::drainOutputBuffer(OMX_BUFFERHEADERTYPE **outHeader) {
566 int32_t index;
567 int32_t Release;
568 AVCFrameIO Output;
569 Output.YCbCr[0] = Output.YCbCr[1] = Output.YCbCr[2] = NULL;
570 AVCDec_Status status =
571 PVAVCDecGetOutput(mHandle, &index, &Release, &Output);
572
573 if (status != AVCDEC_SUCCESS) {
574 return false;
575 }
576
577 PortInfo *port = editPortInfo(1);
578 CHECK_GE(index, 0);
579 CHECK_LT((size_t)index, port->mBuffers.size());
580 CHECK(port->mBuffers.editItemAt(index).mOwnedByUs);
581
582 *outHeader = port->mBuffers.editItemAt(index).mHeader;
583 (*outHeader)->nOffset = 0;
584 (*outHeader)->nFilledLen = port->mDef.nBufferSize;
585 (*outHeader)->nFlags = 0;
586
587 return true;
588}
589
590void SoftAVC::onPortFlushCompleted(OMX_U32 portIndex) {
591 if (portIndex == 0) {
592 PVAVCDecReset(mHandle);
593
594 mEOSStatus = INPUT_DATA_AVAILABLE;
595 }
596}
597
598void SoftAVC::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
599 if (portIndex != 1) {
600 return;
601 }
602
603 switch (mOutputPortSettingsChange) {
604 case NONE:
605 break;
606
607 case AWAITING_DISABLED:
608 {
609 CHECK(!enabled);
610 mOutputPortSettingsChange = AWAITING_ENABLED;
611 break;
612 }
613
614 default:
615 {
616 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
617 CHECK(enabled);
618 mOutputPortSettingsChange = NONE;
619 break;
620 }
621 }
622}
623
624void SoftAVC::updatePortDefinitions() {
625 OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef;
626 def->format.video.nFrameWidth = mWidth;
627 def->format.video.nFrameHeight = mHeight;
628 def->format.video.nStride = def->format.video.nFrameWidth;
629 def->format.video.nSliceHeight = def->format.video.nFrameHeight;
630
631 def = &editPortInfo(1)->mDef;
632 def->format.video.nFrameWidth = mWidth;
633 def->format.video.nFrameHeight = mHeight;
634 def->format.video.nStride = def->format.video.nFrameWidth;
635 def->format.video.nSliceHeight = def->format.video.nFrameHeight;
636
637 def->nBufferSize =
638 (def->format.video.nFrameWidth
639 * def->format.video.nFrameHeight * 3) / 2;
640}
641
642// static
643int32_t SoftAVC::ActivateSPSWrapper(
644 void *userData, unsigned int sizeInMbs, unsigned int numBuffers) {
645 return static_cast<SoftAVC *>(userData)->activateSPS(sizeInMbs, numBuffers);
646}
647
648// static
649int32_t SoftAVC::BindFrameWrapper(
650 void *userData, int32_t index, uint8_t **yuv) {
651 return static_cast<SoftAVC *>(userData)->bindFrame(index, yuv);
652}
653
654// static
655void SoftAVC::UnbindFrame(void *userData, int32_t index) {
656}
657
658int32_t SoftAVC::activateSPS(
659 unsigned int sizeInMbs, unsigned int numBuffers) {
660 PortInfo *port = editPortInfo(1);
661 CHECK_GE(port->mBuffers.size(), numBuffers);
662 CHECK_GE(port->mDef.nBufferSize, (sizeInMbs << 7) * 3);
663
664 return 1;
665}
666
667int32_t SoftAVC::bindFrame(int32_t index, uint8_t **yuv) {
668 PortInfo *port = editPortInfo(1);
669
670 CHECK_GE(index, 0);
671 CHECK_LT((size_t)index, port->mBuffers.size());
672
673 BufferInfo *outBuffer =
674 &port->mBuffers.editItemAt(index);
675
676 CHECK(outBuffer->mOwnedByUs);
677
678 outBuffer->mHeader->nTimeStamp = mCurrentTimeUs;
679 *yuv = outBuffer->mHeader->pBuffer;
680
681 return 1;
682}
683
684} // namespace android
685
686android::SoftOMXComponent *createSoftOMXComponent(
687 const char *name, const OMX_CALLBACKTYPE *callbacks,
688 OMX_PTR appData, OMX_COMPONENTTYPE **component) {
689 return new android::SoftAVC(name, callbacks, appData, component);
690}