#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaDefs.h>
-#include "ffmpeg_utils/ffmpeg_utils.h"
-
-#undef realloc
-#include <stdlib.h>
+#include "utils/ffmpeg_utils.h"
#define DEBUG_PKT 0
#define DEBUG_FRM 0
params->nVersion.s.nStep = 0;
}
+void SoftFFmpegVideo::setMode(const char *name) {
+ if (!strcmp(name, "OMX.ffmpeg.mpeg2v.decoder")) {
+ mMode = MODE_MPEG2;
+ } else if (!strcmp(name, "OMX.ffmpeg.h263.decoder")) {
+ mMode = MODE_H263;
+ } else if (!strcmp(name, "OMX.ffmpeg.mpeg4.decoder")) {
+ mMode = MODE_MPEG4;
+ } else if (!strcmp(name, "OMX.ffmpeg.wmv.decoder")) {
+ mMode = MODE_WMV;
+ } else if (!strcmp(name, "OMX.ffmpeg.rv.decoder")) {
+ mMode = MODE_RV;
+ } else if (!strcmp(name, "OMX.ffmpeg.h264.decoder")) {
+ mMode = MODE_H264;
+ } else if (!strcmp(name, "OMX.ffmpeg.vpx.decoder")) {
+ mMode = MODE_VPX;
+ } else if (!strcmp(name, "OMX.ffmpeg.vc1.decoder")) {
+ mMode = MODE_VC1;
+ } else if (!strcmp(name, "OMX.ffmpeg.flv1.decoder")) {
+ mMode = MODE_FLV1;
+ } else if (!strcmp(name, "OMX.ffmpeg.divx.decoder")) {
+ mMode = MODE_DIVX;
+ } else if (!strcmp(name, "OMX.ffmpeg.hevc.decoder")) {
+ mMode = MODE_HEVC;
+ } else if (!strcmp(name, "OMX.ffmpeg.vtrial.decoder")) {
+ mMode = MODE_TRIAL;
+ } else {
+ TRESPASS();
+ }
+}
+
SoftFFmpegVideo::SoftFFmpegVideo(
const char *name,
const OMX_CALLBACKTYPE *callbacks,
OMX_PTR appData,
OMX_COMPONENTTYPE **component)
: SimpleSoftOMXComponent(name, callbacks, appData, component),
- mMode(MODE_H264),
+ mMode(MODE_NONE),
+ mFFmpegAlreadyInited(false),
+ mCodecAlreadyOpened(false),
+ mPendingFrameAsSettingChanged(false),
mCtx(NULL),
mImgConvertCtx(NULL),
+ mFrame(NULL),
+ mEOSStatus(INPUT_DATA_AVAILABLE),
mExtradataReady(false),
mIgnoreExtradata(false),
mSignalledError(false),
+ mDoDeinterlace(true),
mWidth(320),
mHeight(240),
mStride(320),
mOutputPortSettingsChange(NONE) {
- if (!strcmp(name, "OMX.ffmpeg.mpeg4.decoder")) {
- mMode = MODE_MPEG4;
- } else if (!strcmp(name, "OMX.ffmpeg.mpeg2v.decoder")) {
- mMode = MODE_MPEG2;
- } else if (!strcmp(name, "OMX.ffmpeg.h263.decoder")) {
- mMode = MODE_H263;
- } else if (!strcmp(name, "OMX.ffmpeg.vc1.decoder")) {
- mMode = MODE_VC1;
- } else {
- CHECK(!strcmp(name, "OMX.ffmpeg.h264.decoder"));
- //mIgnoreExtradata = true;
- }
- LOGV("SoftFFmpegVideo component: %s", name);
+ setMode(name);
+
+ ALOGD("SoftFFmpegVideo component: %s mMode: %d", name, mMode);
initPorts();
CHECK_EQ(initDecoder(), (status_t)OK);
}
SoftFFmpegVideo::~SoftFFmpegVideo() {
- LOGV("~SoftFFmpegVideo");
+ ALOGV("~SoftFFmpegVideo");
deInitDecoder();
- deInitFFmpeg();
+ if (mFFmpegAlreadyInited) {
+ deInitFFmpeg();
+ }
}
-void SoftFFmpegVideo::initPorts() {
- OMX_PARAM_PORTDEFINITIONTYPE def;
- InitOMXParams(&def);
-
- def.nPortIndex = 0;
- def.eDir = OMX_DirInput;
- def.nBufferCountMin = kNumInputBuffers;
- def.nBufferCountActual = def.nBufferCountMin;
- def.nBufferSize = 1280 * 720; // 256 * 1024?
- def.bEnabled = OMX_TRUE;
- def.bPopulated = OMX_FALSE;
- def.eDomain = OMX_PortDomainVideo;
- def.bBuffersContiguous = OMX_FALSE;
- def.nBufferAlignment = 1;
-
- switch (mMode) {
- case MODE_H264:
- def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_AVC);
- def.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
- break;
- case MODE_MPEG4:
- def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_MPEG4);
- def.format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG4;
- break;
+void SoftFFmpegVideo::initInputFormat(uint32_t mode,
+ OMX_PARAM_PORTDEFINITIONTYPE &def) {
+ switch (mode) {
case MODE_MPEG2:
def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_MPEG2);
def.format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG2;
def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_H263);
def.format.video.eCompressionFormat = OMX_VIDEO_CodingH263;
break;
+ case MODE_MPEG4:
+ def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_MPEG4);
+ def.format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG4;
+ break;
+ case MODE_WMV:
+ def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_WMV);
+ def.format.video.eCompressionFormat = OMX_VIDEO_CodingWMV;
+ break;
+ case MODE_RV:
+ def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RV);
+ def.format.video.eCompressionFormat = OMX_VIDEO_CodingRV;
+ break;
+ case MODE_H264:
+ def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_AVC);
+ def.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
+ break;
+ case MODE_VPX:
+ def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_VPX);
+ def.format.video.eCompressionFormat = OMX_VIDEO_CodingVPX;
+ break;
case MODE_VC1:
def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_VC1);
def.format.video.eCompressionFormat = OMX_VIDEO_CodingWMV;
break;
+ case MODE_FLV1:
+ def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_FLV1);
+ def.format.video.eCompressionFormat = OMX_VIDEO_CodingFLV1;
+ break;
+ case MODE_DIVX:
+ def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_DIVX);
+ def.format.video.eCompressionFormat = OMX_VIDEO_CodingDIVX;
+ break;
+ case MODE_HEVC:
+ def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_HEVC);
+ def.format.video.eCompressionFormat = OMX_VIDEO_CodingHEVC;
+ break;
+ case MODE_TRIAL:
+ def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_FFMPEG);
+ def.format.video.eCompressionFormat = OMX_VIDEO_CodingAutoDetect;
+ break;
default:
CHECK(!"Should not be here. Unsupported mime type and compression format");
break;
def.format.video.bFlagErrorConcealment = OMX_FALSE;
def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
def.format.video.pNativeWindow = NULL;
+}
+
+void SoftFFmpegVideo::initPorts() {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+
+ def.nPortIndex = 0;
+ def.eDir = OMX_DirInput;
+ def.nBufferCountMin = kNumInputBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.nBufferSize = 1280 * 720; // 256 * 1024?
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainVideo;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 1;
+
+ initInputFormat(mMode, def);
addPort(def);
addPort(def);
}
-static int lockmgr(void **mtx, enum AVLockOp op) {
- switch(op) {
- case AV_LOCK_CREATE:
- *mtx = (void *)SDL_CreateMutex();
- if(!*mtx)
- return 1;
- return 0;
- case AV_LOCK_OBTAIN:
- return !!SDL_LockMutex((SDL_mutex *)*mtx);
- case AV_LOCK_RELEASE:
- return !!SDL_UnlockMutex((SDL_mutex *)*mtx);
- case AV_LOCK_DESTROY:
- SDL_DestroyMutex((SDL_mutex *)*mtx);
- return 0;
- }
- return 1;
-}
-
-status_t SoftFFmpegVideo::initFFmpeg() {
- //nam_av_log_set_flags(AV_LOG_SKIP_REPEATED);
- av_log_set_level(AV_LOG_DEBUG);
- av_log_set_callback(nam_av_log_callback);
-
- /* register all codecs, demux and protocols */
- avcodec_register_all();
-#if CONFIG_AVDEVICE
- avdevice_register_all();
-#endif
- av_register_all();
- avformat_network_init();
-
- init_opts();
-
- if (av_lockmgr_register(lockmgr)) {
- LOGE("could not initialize lock manager!");
- return NO_INIT;
- }
-
- return OK;
-}
-
-void SoftFFmpegVideo::deInitFFmpeg() {
- av_lockmgr_register(NULL);
- uninit_opts();
- avformat_network_deinit();
-}
-
-
-void SoftFFmpegVideo::setAVCtxToDefault(AVCodecContext *avctx, const AVCodec *codec) {
+void SoftFFmpegVideo::setDefaultCtx(AVCodecContext *avctx, const AVCodec *codec) {
int fast = 0;
avctx->workaround_bugs = 1;
avctx->lowres = 0;
if(avctx->lowres > codec->max_lowres){
- LOGW("The maximum value for lowres supported by the decoder is %d",
+ ALOGW("The maximum value for lowres supported by the decoder is %d",
codec->max_lowres);
avctx->lowres= codec->max_lowres;
}
status_t status;
status = initFFmpeg();
- if (status != OK)
- return status;
+ if (status != OK) {
+ return NO_INIT;
+ }
+ mFFmpegAlreadyInited = true;
mCtx = avcodec_alloc_context3(NULL);
if (!mCtx)
{
- LOGE("avcodec_alloc_context failed.");
- return OMX_ErrorInsufficientResources;
+ ALOGE("avcodec_alloc_context failed.");
+ return NO_MEMORY;
}
mCtx->codec_type = AVMEDIA_TYPE_VIDEO;
switch (mMode) {
- case MODE_H264:
- mCtx->codec_id = CODEC_ID_H264;
+ case MODE_MPEG2:
+ mCtx->codec_id = AV_CODEC_ID_MPEG2VIDEO;
+ break;
+ case MODE_H263:
+ mCtx->codec_id = AV_CODEC_ID_H263;
+ //FIXME, which?
+ //mCtx->codec_id = AV_CODEC_ID_H263P;
+ //mCtx->codec_id = AV_CODEC_ID_H263I;
break;
case MODE_MPEG4:
- mCtx->codec_id = CODEC_ID_MPEG4;
+ mCtx->codec_id = AV_CODEC_ID_MPEG4;
break;
- case MODE_MPEG2:
- mCtx->codec_id = CODEC_ID_MPEG2VIDEO;
+ case MODE_WMV:
+ mCtx->codec_id = AV_CODEC_ID_WMV2; // default, adjust in "internalSetParameter" fxn
break;
- case MODE_H263:
- mCtx->codec_id = CODEC_ID_H263;
- // TODO, which?
- //mCtx->codec_id = CODEC_ID_H263P;
- //mCtx->codec_id = CODEC_ID_H263I;
+ case MODE_RV:
+ mCtx->codec_id = AV_CODEC_ID_RV40; // default, adjust in "internalSetParameter" fxn
+ break;
+ case MODE_H264:
+ mCtx->codec_id = AV_CODEC_ID_H264;
+ break;
+ case MODE_VPX:
+ mCtx->codec_id = AV_CODEC_ID_VP8;
break;
case MODE_VC1:
- mCtx->codec_id = CODEC_ID_VC1;
+ mCtx->codec_id = AV_CODEC_ID_VC1;
+ break;
+ case MODE_FLV1:
+ mCtx->codec_id = AV_CODEC_ID_FLV1;
+ break;
+ case MODE_DIVX:
+ mCtx->codec_id = AV_CODEC_ID_MPEG4;
+ break;
+ case MODE_HEVC:
+ mCtx->codec_id = AV_CODEC_ID_HEVC;
+ break;
+ case MODE_TRIAL:
+ mCtx->codec_id = AV_CODEC_ID_NONE;
break;
default:
CHECK(!"Should not be here. Unsupported codec");
break;
}
- mCtx->codec = avcodec_find_decoder(mCtx->codec_id);
- if (!mCtx->codec)
- {
- LOGE("find codec failed");
- return OMX_ErrorNotImplemented;
- }
-
- setAVCtxToDefault(mCtx, mCtx->codec);
-
mCtx->extradata_size = 0;
mCtx->extradata = NULL;
mCtx->width = mWidth;
mCtx->height = mHeight;
-#if 0
- // FIXME, defer to open? ref: OMXCodec.cpp:setVideoOutputFormat
- err = avcodec_open2(mCtx, mCtx->codec, NULL);
- if (err < 0) {
- LOGE("ffmpeg video decoder failed to initialize. (%d)", err);
- return OMX_ErrorUndefined;
- }
-#endif
-
- return OMX_ErrorNone;
+ return OK;
}
void SoftFFmpegVideo::deInitDecoder() {
if (mCtx) {
- avcodec_flush_buffers(mCtx);
- if (!mCtx->extradata) {
+ if (avcodec_is_open(mCtx)) {
+ avcodec_flush_buffers(mCtx);
+ }
+ if (mCtx->extradata) {
av_free(mCtx->extradata);
mCtx->extradata = NULL;
mCtx->extradata_size = 0;
}
- avcodec_close(mCtx);
- av_free(mCtx);
- mCtx = NULL;
+ if (mCodecAlreadyOpened) {
+ avcodec_close(mCtx);
+ av_free(mCtx);
+ mCtx = NULL;
+ }
+ }
+ if (mFrame) {
+ av_freep(&mFrame);
+ mFrame = NULL;
}
-
if (mImgConvertCtx) {
sws_freeContext(mImgConvertCtx);
mImgConvertCtx = NULL;
}
}
+void SoftFFmpegVideo::getInputFormat(uint32_t mode,
+ OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams) {
+ switch (mode) {
+ case MODE_MPEG2:
+ formatParams->eCompressionFormat = OMX_VIDEO_CodingMPEG2;
+ break;
+ case MODE_H263:
+ formatParams->eCompressionFormat = OMX_VIDEO_CodingH263;
+ break;
+ case MODE_MPEG4:
+ formatParams->eCompressionFormat = OMX_VIDEO_CodingMPEG4;
+ break;
+ case MODE_WMV:
+ formatParams->eCompressionFormat = OMX_VIDEO_CodingWMV;
+ break;
+ case MODE_RV:
+ formatParams->eCompressionFormat = OMX_VIDEO_CodingRV;
+ break;
+ case MODE_H264:
+ formatParams->eCompressionFormat = OMX_VIDEO_CodingAVC;
+ break;
+ case MODE_VPX:
+ formatParams->eCompressionFormat = OMX_VIDEO_CodingVPX;
+ break;
+ case MODE_VC1:
+ formatParams->eCompressionFormat = OMX_VIDEO_CodingVC1;
+ break;
+ case MODE_FLV1:
+ formatParams->eCompressionFormat = OMX_VIDEO_CodingFLV1;
+ break;
+ case MODE_DIVX:
+ formatParams->eCompressionFormat = OMX_VIDEO_CodingDIVX;
+ break;
+ case MODE_HEVC:
+ formatParams->eCompressionFormat = OMX_VIDEO_CodingHEVC;
+ break;
+ case MODE_TRIAL:
+ formatParams->eCompressionFormat = OMX_VIDEO_CodingAutoDetect;
+ break;
+ default:
+ CHECK(!"Should not be here. Unsupported compression format.");
+ break;
+ }
+ formatParams->eColorFormat = OMX_COLOR_FormatUnused;
+ formatParams->xFramerate = 0;
+}
+
OMX_ERRORTYPE SoftFFmpegVideo::internalGetParameter(
OMX_INDEXTYPE index, OMX_PTR params) {
+ //ALOGV("internalGetParameter index:0x%x", index);
switch (index) {
case OMX_IndexParamVideoPortFormat:
{
OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
(OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
- if (formatParams->nPortIndex > 1) {
+ if (formatParams->nPortIndex > kOutputPortIndex) {
return OMX_ErrorUndefined;
}
return OMX_ErrorNoMore;
}
- if (formatParams->nPortIndex == 0) {
- switch (mMode) {
- case MODE_H264:
- formatParams->eCompressionFormat = OMX_VIDEO_CodingAVC;
- break;
- case MODE_MPEG4:
- formatParams->eCompressionFormat = OMX_VIDEO_CodingMPEG4;
- break;
- case MODE_MPEG2:
- formatParams->eCompressionFormat = OMX_VIDEO_CodingMPEG2;
- break;
- case MODE_H263:
- formatParams->eCompressionFormat = OMX_VIDEO_CodingH263;
- break;
- case MODE_VC1:
- formatParams->eCompressionFormat = OMX_VIDEO_CodingWMV;
- break;
- default:
- CHECK(!"Should not be here. Unsupported compression format.");
- break;
- }
- formatParams->eColorFormat = OMX_COLOR_FormatUnused;
- formatParams->xFramerate = 0;
+ if (formatParams->nPortIndex == kInputPortIndex) {
+ getInputFormat(mMode, formatParams);
} else {
- CHECK_EQ(formatParams->nPortIndex, 1u);
+ CHECK_EQ(formatParams->nPortIndex, kOutputPortIndex);
formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
return OMX_ErrorNone;
}
+ case OMX_IndexParamVideoWmv:
+ {
+ OMX_VIDEO_PARAM_WMVTYPE *profile =
+ (OMX_VIDEO_PARAM_WMVTYPE *)params;
+
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ profile->eFormat = OMX_VIDEO_WMVFormatUnused;
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamVideoRv:
+ {
+ OMX_VIDEO_PARAM_RVTYPE *profile =
+ (OMX_VIDEO_PARAM_RVTYPE *)params;
+
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ profile->eFormat = OMX_VIDEO_RVFormatUnused;
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamVideoFFmpeg:
+ {
+ OMX_VIDEO_PARAM_FFMPEGTYPE *profile =
+ (OMX_VIDEO_PARAM_FFMPEGTYPE *)params;
+
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ profile->eCodecId = AV_CODEC_ID_NONE;
+ profile->nWidth = 0;
+ profile->nHeight = 0;
+
+ return OMX_ErrorNone;
+ }
+
default:
+
return SimpleSoftOMXComponent::internalGetParameter(index, params);
}
}
+OMX_ERRORTYPE SoftFFmpegVideo::isRoleSupported(
+ const OMX_PARAM_COMPONENTROLETYPE *roleParams) {
+ bool supported = true;
+
+ switch (mMode) {
+ case MODE_MPEG2:
+ if (strncmp((const char *)roleParams->cRole,
+ "video_decoder.mpeg2v", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
+ break;
+ case MODE_H263:
+ if (strncmp((const char *)roleParams->cRole,
+ "video_decoder.h263", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
+ break;
+ case MODE_MPEG4:
+ if (strncmp((const char *)roleParams->cRole,
+ "video_decoder.mpeg4", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
+ break;
+ case MODE_WMV:
+ if (strncmp((const char *)roleParams->cRole,
+ "video_decoder.wmv", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
+ break;
+ case MODE_RV:
+ if (strncmp((const char *)roleParams->cRole,
+ "video_decoder.rv", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
+ break;
+ case MODE_H264:
+ if (strncmp((const char *)roleParams->cRole,
+ "video_decoder.avc", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
+ break;
+ case MODE_VPX:
+ if (strncmp((const char *)roleParams->cRole,
+ "video_decoder.vpx", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
+ break;
+ case MODE_VC1:
+ if (strncmp((const char *)roleParams->cRole,
+ "video_decoder.vc1", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
+ break;
+ case MODE_FLV1:
+ if (strncmp((const char *)roleParams->cRole,
+ "video_decoder.flv1", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
+ break;
+ case MODE_DIVX:
+ if (strncmp((const char *)roleParams->cRole,
+ "video_decoder.divx", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
+ break;
+ case MODE_HEVC:
+ if (strncmp((const char *)roleParams->cRole,
+ "video_decoder.hevc", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
+ break;
+ case MODE_TRIAL:
+ if (strncmp((const char *)roleParams->cRole,
+ "video_decoder.trial", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
+ break;
+ default:
+ CHECK(!"Should not be here. Unsupported role.");
+ break;
+ }
+
+ if (!supported) {
+ ALOGE("unsupported role: %s", (const char *)roleParams->cRole);
+ return OMX_ErrorUndefined;
+ }
+ return OMX_ErrorNone;
+}
+
OMX_ERRORTYPE SoftFFmpegVideo::internalSetParameter(
OMX_INDEXTYPE index, const OMX_PTR params) {
+ //ALOGV("internalSetParameter index:0x%x", index);
switch (index) {
case OMX_IndexParamStandardComponentRole:
{
const OMX_PARAM_COMPONENTROLETYPE *roleParams =
(const OMX_PARAM_COMPONENTROLETYPE *)params;
-
- bool supported = true;
- switch (mMode) {
- case MODE_H264:
- if (strncmp((const char *)roleParams->cRole,
- "video_decoder.avc", OMX_MAX_STRINGNAME_SIZE - 1))
- supported = false;
- break;
- case MODE_MPEG4:
- if (strncmp((const char *)roleParams->cRole,
- "video_decoder.mpeg4", OMX_MAX_STRINGNAME_SIZE - 1))
- supported = false;
- break;
- case MODE_MPEG2:
- if (strncmp((const char *)roleParams->cRole,
- "video_decoder.mpeg2v", OMX_MAX_STRINGNAME_SIZE - 1))
- supported = false;
- break;
- case MODE_H263:
- if (strncmp((const char *)roleParams->cRole,
- "video_decoder.h263", OMX_MAX_STRINGNAME_SIZE - 1))
- supported = false;
- break;
- case MODE_VC1:
- if (strncmp((const char *)roleParams->cRole,
- "video_decoder.vc1", OMX_MAX_STRINGNAME_SIZE - 1))
- supported = false;
- break;
- default:
- CHECK(!"Should not be here. Unsupported role.");
- break;
- }
- if (!supported) {
- LOGE("unsupported role: %s", (const char *)roleParams->cRole);
- return OMX_ErrorUndefined;
- }
-
- return OMX_ErrorNone;
+ return isRoleSupported(roleParams);
}
case OMX_IndexParamVideoPortFormat:
OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
(OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
- if (formatParams->nPortIndex > 1) {
+ if (formatParams->nPortIndex > kOutputPortIndex) {
return OMX_ErrorUndefined;
}
OMX_PARAM_PORTDEFINITIONTYPE *defParams =
(OMX_PARAM_PORTDEFINITIONTYPE *)params;
- if (defParams->nPortIndex > 1 ||
+ if (defParams->nPortIndex > kOutputPortIndex ||
defParams->nSize != sizeof(OMX_PARAM_PORTDEFINITIONTYPE)) {
return OMX_ErrorUndefined;
}
CHECK_EQ((int)defParams->eDomain, (int)OMX_PortDomainVideo);
- // only care about input port
- if (defParams->nPortIndex == kPortIndexOutput) {
+ //only care about input port
+ if (defParams->nPortIndex == kOutputPortIndex) {
OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &defParams->format.video;
- mWidth = video_def->nFrameWidth;
- mHeight = video_def->nFrameHeight;
- LOGV("got OMX_IndexParamPortDefinition, mWidth: %d, mHeight: %d",
- mWidth, mHeight);
+ mCtx->width = video_def->nFrameWidth;
+ mCtx->height = video_def->nFrameHeight;
+ ALOGV("got OMX_IndexParamPortDefinition, width: %lu, height: %lu",
+ video_def->nFrameWidth, video_def->nFrameHeight);
return OMX_ErrorNone;
}
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamVideoWmv:
+ {
+ OMX_VIDEO_PARAM_WMVTYPE *profile =
+ (OMX_VIDEO_PARAM_WMVTYPE *)params;
+
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (profile->eFormat == OMX_VIDEO_WMVFormat7) {
+ mCtx->codec_id = AV_CODEC_ID_WMV1;
+ } else if (profile->eFormat == OMX_VIDEO_WMVFormat8) {
+ mCtx->codec_id = AV_CODEC_ID_WMV2;
+ } else if (profile->eFormat == OMX_VIDEO_WMVFormat9) {
+ mCtx->codec_id = AV_CODEC_ID_WMV3;
+ } else {
+ ALOGE("unsupported wmv codec: 0x%x", profile->eFormat);
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamVideoRv:
+ {
+ OMX_VIDEO_PARAM_RVTYPE *profile =
+ (OMX_VIDEO_PARAM_RVTYPE *)params;
+
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (profile->eFormat == OMX_VIDEO_RVFormatG2) {
+ mCtx->codec_id = AV_CODEC_ID_RV20;
+ } else if (profile->eFormat == OMX_VIDEO_RVFormat8) {
+ mCtx->codec_id = AV_CODEC_ID_RV30;
+ } else if (profile->eFormat == OMX_VIDEO_RVFormat9) {
+ mCtx->codec_id = AV_CODEC_ID_RV40;
+ } else {
+ ALOGE("unsupported rv codec: 0x%x", profile->eFormat);
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamVideoFFmpeg:
+ {
+ OMX_VIDEO_PARAM_FFMPEGTYPE *profile =
+ (OMX_VIDEO_PARAM_FFMPEGTYPE *)params;
+
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ mCtx->codec_id = (enum AVCodecID)profile->eCodecId;
+ mCtx->width = profile->nWidth;
+ mCtx->height = profile->nHeight;
+
+ ALOGD("got OMX_IndexParamVideoFFmpeg, "
+ "eCodecId:%ld(%s), width:%lu, height:%lu",
+ profile->eCodecId,
+ avcodec_get_name(mCtx->codec_id),
+ profile->nWidth,
+ profile->nHeight);
+
+ return OMX_ErrorNone;
}
default:
+
return SimpleSoftOMXComponent::internalSetParameter(index, params);
}
}
-void SoftFFmpegVideo::onQueueFilled(OMX_U32 portIndex) {
- int err = 0;
+bool SoftFFmpegVideo::handlePortSettingChangeEvent() {
+ if (mCtx->width != mWidth || mCtx->height != mHeight) {
+ ALOGI("ffmpeg video port setting change event(%dx%d)->(%dx%d).",
+ mWidth, mHeight, mCtx->width, mCtx->height);
- if (mSignalledError || mOutputPortSettingsChange != NONE) {
- return;
- }
+ mWidth = mCtx->width;
+ mHeight = mCtx->height;
+ mStride = mWidth;
- List<BufferInfo *> &inQueue = getPortQueue(0);
- List<BufferInfo *> &outQueue = getPortQueue(1);
+ updatePortDefinitions();
+ notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+ mOutputPortSettingsChange = AWAITING_DISABLED;
+ return true;
+ }
- while (!inQueue.empty() && !outQueue.empty()) {
- BufferInfo *inInfo = *inQueue.begin();
- OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+ return false;
+}
- BufferInfo *outInfo = *outQueue.begin();
- OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+int32_t SoftFFmpegVideo::handleExtradata() {
+ List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
- if (mCtx->width != mWidth || mCtx->height != mHeight) {
- mCtx->width = mWidth;
- mCtx->height = mHeight;
- mStride = mWidth;
+ ALOGI("got extradata, ignore: %d, size: %lu",
+ mIgnoreExtradata, inHeader->nFilledLen);
+ hexdump(inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
- updatePortDefinitions();
+ if (mIgnoreExtradata) {
+ ALOGI("got extradata, size: %lu, but ignore it", inHeader->nFilledLen);
+ } else {
+ if (!mExtradataReady) {
+ //if (mMode == MODE_H264)
+ //it is possible to receive multiple input buffer with OMX_BUFFERFLAG_CODECCONFIG flag.
+ //for example, H264, the first input buffer is SPS, and another is PPS!
+ int orig_extradata_size = mCtx->extradata_size;
+ mCtx->extradata_size += inHeader->nFilledLen;
+ mCtx->extradata = (uint8_t *)realloc(mCtx->extradata,
+ mCtx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!mCtx->extradata) {
+ ALOGE("ffmpeg video decoder failed to alloc extradata memory.");
+ return ERR_OOM;
+ }
- notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
- mOutputPortSettingsChange = AWAITING_DISABLED;
- return;
+ memcpy(mCtx->extradata + orig_extradata_size,
+ inHeader->pBuffer + inHeader->nOffset,
+ inHeader->nFilledLen);
+ memset(mCtx->extradata + mCtx->extradata_size, 0,
+ FF_INPUT_BUFFER_PADDING_SIZE);
}
+ }
- if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
- inQueue.erase(inQueue.begin());
- inInfo->mOwnedByUs = false;
- notifyEmptyBufferDone(inHeader);
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
- outHeader->nFilledLen = 0;
- outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+ return ERR_OK;
+}
- outQueue.erase(outQueue.begin());
- outInfo->mOwnedByUs = false;
- notifyFillBufferDone(outHeader);
- return;
- }
+int32_t SoftFFmpegVideo::openDecoder() {
+ if (mCodecAlreadyOpened) {
+ return ERR_OK;
+ }
- if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
- LOGI("got extradata, ignore: %d, size: %lu", mIgnoreExtradata, inHeader->nFilledLen);
- hexdump(inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
- if (!mExtradataReady && !mIgnoreExtradata) {
- //if (mMode == MODE_H264)
- // it is possible to receive multiple input buffer with OMX_BUFFERFLAG_CODECCONFIG flag.
- // for example, H264, the first input buffer is SPS, and another is PPS!
- int orig_extradata_size = mCtx->extradata_size;
- mCtx->extradata_size += inHeader->nFilledLen;
- mCtx->extradata = (uint8_t *)realloc(mCtx->extradata,
- mCtx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!mCtx->extradata) {
- LOGE("ffmpeg video decoder failed to alloc extradata memory.");
- notify(OMX_EventError, OMX_ErrorInsufficientResources, 0, NULL);
- mSignalledError = true;
- return;
- }
+ if (!mExtradataReady) {
+ ALOGI("extradata is ready, size: %d", mCtx->extradata_size);
+ hexdump(mCtx->extradata, mCtx->extradata_size);
+ mExtradataReady = true;
+ }
- memcpy(mCtx->extradata + orig_extradata_size,
- inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
- memset(mCtx->extradata + mCtx->extradata_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+ //find decoder again as codec_id may have changed
+ mCtx->codec = avcodec_find_decoder(mCtx->codec_id);
+ if (!mCtx->codec) {
+ ALOGE("ffmpeg video decoder failed to find codec");
+ return ERR_CODEC_NOT_FOUND;
+ }
- inInfo->mOwnedByUs = false;
- inQueue.erase(inQueue.begin());
- inInfo = NULL;
- notifyEmptyBufferDone(inHeader);
- inHeader = NULL;
+ setDefaultCtx(mCtx, mCtx->codec);
- continue;
- }
+ ALOGD("begin to open ffmpeg decoder(%s) now",
+ avcodec_get_name(mCtx->codec_id));
- if (mIgnoreExtradata) {
- LOGI("got extradata, size: %lu, but ignore it", inHeader->nFilledLen);
- inInfo->mOwnedByUs = false;
- inQueue.erase(inQueue.begin());
- inInfo = NULL;
- notifyEmptyBufferDone(inHeader);
- inHeader = NULL;
+ int err = avcodec_open2(mCtx, mCtx->codec, NULL);
+ if (err < 0) {
+ ALOGE("ffmpeg video decoder failed to initialize. (%s)", av_err2str(err));
+ return ERR_DECODER_OPEN_FAILED;
+ }
+ mCodecAlreadyOpened = true;
- continue;
+ ALOGD("open ffmpeg video decoder(%s) success",
+ avcodec_get_name(mCtx->codec_id));
+
+ mFrame = avcodec_alloc_frame();
+ if (!mFrame) {
+ ALOGE("oom for video frame");
+ return ERR_OOM;
+ }
+
+ return ERR_OK;
+}
+
+void SoftFFmpegVideo::initPacket(AVPacket *pkt,
+ OMX_BUFFERHEADERTYPE *inHeader) {
+ memset(pkt, 0, sizeof(AVPacket));
+ av_init_packet(pkt);
+
+ if (inHeader) {
+ pkt->data = (uint8_t *)inHeader->pBuffer + inHeader->nOffset;
+ pkt->size = inHeader->nFilledLen;
+ pkt->pts = inHeader->nTimeStamp;
+ } else {
+ pkt->data = NULL;
+ pkt->size = 0;
+ pkt->pts = AV_NOPTS_VALUE;
+ }
+
+#if DEBUG_PKT
+ if (pkt->pts != AV_NOPTS_VALUE)
+ {
+ ALOGV("pkt size:%d, pts:%lld", pkt->size, pkt->pts);
+ } else {
+ ALOGV("pkt size:%d, pts:N/A", pkt->size);
+ }
+#endif
+}
+
+int32_t SoftFFmpegVideo::decodeVideo() {
+ int len = 0;
+ int gotPic = false;
+ int32_t ret = ERR_OK;
+ bool is_flush = (mEOSStatus != INPUT_DATA_AVAILABLE);
+ List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
+ BufferInfo *inInfo = NULL;
+ OMX_BUFFERHEADERTYPE *inHeader = NULL;
+
+ if (!is_flush) {
+ inInfo = *inQueue.begin();
+ CHECK(inInfo != NULL);
+ inHeader = inInfo->mHeader;
+ }
+
+ AVPacket pkt;
+ initPacket(&pkt, inHeader);
+ //av_frame_unref(mFrame); //Don't unref mFrame!!!
+ avcodec_get_frame_defaults(mFrame);
+
+ int err = avcodec_decode_video2(mCtx, mFrame, &gotPic, &pkt);
+ if (err < 0) {
+ ALOGE("ffmpeg video decoder failed to decode frame. (%d)", err);
+ //don't send error to OMXCodec, skip!
+ ret = ERR_NO_FRM;
+ } else {
+ if (!gotPic) {
+ ALOGI("ffmpeg video decoder failed to get frame.");
+ //stop sending empty packets if the decoder is finished
+ if (is_flush && mCtx->codec->capabilities & CODEC_CAP_DELAY) {
+ ret = ERR_FLUSHED;
+ } else {
+ ret = ERR_NO_FRM;
+ }
+ } else {
+ if (handlePortSettingChangeEvent()) {
+ mPendingFrameAsSettingChanged = true;
}
+ ret = ERR_OK;
}
+ }
- AVPacket pkt;
- av_init_packet(&pkt);
- pkt.data = (uint8_t *)inHeader->pBuffer + inHeader->nOffset;
- pkt.size = inHeader->nFilledLen;
- pkt.pts = inHeader->nTimeStamp;
-#if DEBUG_PKT
- LOGV("pkt size: %d, pts: %lld", pkt.size, pkt.pts);
+ if (!is_flush) {
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+ }
+
+ return ret;
+}
+
+int32_t SoftFFmpegVideo::preProcessVideoFrame(AVPicture *picture, void **bufp) {
+ AVPicture *picture2;
+ AVPicture picture_tmp;
+ uint8_t *buf = NULL;
+
+ //deinterlace : must be done before any resize
+ if (mDoDeinterlace) {
+ int size = 0;
+
+ //create temporary picture
+ size = avpicture_get_size(mCtx->pix_fmt, mCtx->width, mCtx->height);
+ buf = (uint8_t *)av_malloc(size);
+ if (!buf) {
+ ALOGE("oom for temporary picture");
+ return ERR_OOM;
+ }
+
+ picture2 = &picture_tmp;
+ avpicture_fill(picture2, buf, mCtx->pix_fmt, mCtx->width, mCtx->height);
+
+ if (avpicture_deinterlace(picture2, picture,
+ mCtx->pix_fmt, mCtx->width, mCtx->height) < 0) {
+ //if error, do not deinterlace
+ ALOGE("Deinterlacing failed");
+ av_free(buf);
+ buf = NULL;
+ picture2 = picture;
+ }
+ } else {
+ picture2 = picture;
+ }
+
+ if (picture != picture2)
+ *picture = *picture2;
+ *bufp = buf;
+
+ return ERR_OK;
+}
+
+int32_t SoftFFmpegVideo::drainOneOutputBuffer() {
+ List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+ BufferInfo *outInfo = *outQueue.begin();
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+ AVPicture pict;
+ void *buffer_to_free = NULL;
+ int64_t pts = AV_NOPTS_VALUE;
+ uint8_t *dst = outHeader->pBuffer;
+
+ //do deinterlace if necessary. for example, your TV is progressive
+ int32_t err = preProcessVideoFrame((AVPicture *)mFrame, &buffer_to_free);
+ if (err != ERR_OK) {
+ ALOGE("preProcessVideoFrame failed");
+ return err;
+ }
+
+ memset(&pict, 0, sizeof(AVPicture));
+ pict.data[0] = dst;
+ pict.data[1] = dst + mStride * mHeight;
+ pict.data[2] = pict.data[1] + (mStride / 2 * mHeight / 2);
+ pict.linesize[0] = mStride;
+ pict.linesize[1] = mStride / 2;
+ pict.linesize[2] = mStride / 2;
+
+ int sws_flags = SWS_BICUBIC;
+ mImgConvertCtx = sws_getCachedContext(mImgConvertCtx,
+ mWidth, mHeight, mCtx->pix_fmt, mWidth, mHeight,
+ PIX_FMT_YUV420P, sws_flags, NULL, NULL, NULL);
+ if (mImgConvertCtx == NULL) {
+ ALOGE("Cannot initialize the conversion context");
+ av_free(buffer_to_free);
+ return ERR_SWS_FAILED;
+ }
+ sws_scale(mImgConvertCtx, mFrame->data, mFrame->linesize,
+ 0, mHeight, pict.data, pict.linesize);
+
+ outHeader->nOffset = 0;
+ outHeader->nFilledLen = (mStride * mHeight * 3) / 2;
+ outHeader->nFlags = 0;
+ if (mFrame->key_frame) {
+ outHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
+ }
+
+ //process timestamps
+ if (decoder_reorder_pts == -1) {
+ pts = *(int64_t*)av_opt_ptr(avcodec_get_frame_class(),
+ mFrame, "best_effort_timestamp");
+ } else if (decoder_reorder_pts) {
+ pts = mFrame->pkt_pts;
+ } else {
+ pts = mFrame->pkt_dts;
+ }
+
+ if (pts == AV_NOPTS_VALUE) {
+ pts = 0;
+ }
+ outHeader->nTimeStamp = pts;
+
+#if DEBUG_FRM
+ ALOGV("mFrame pts: %lld", pts);
#endif
- if (!mExtradataReady) {
- LOGI("extradata is ready");
- hexdump(mCtx->extradata, mCtx->extradata_size);
- LOGI("open ffmpeg decoder now");
- mExtradataReady = true;
-
- err = avcodec_open2(mCtx, mCtx->codec, NULL);
- if (err < 0) {
- LOGE("ffmpeg video decoder failed to initialize. (%d)", err);
+
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+
+ av_free(buffer_to_free);
+
+ return ERR_OK;
+}
+
+void SoftFFmpegVideo::drainEOSOutputBuffer() {
+ List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+ BufferInfo *outInfo = *outQueue.begin();
+ CHECK(outInfo != NULL);
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+ ALOGD("ffmpeg video decoder fill eos outbuf");
+
+ outHeader->nTimeStamp = 0;
+ outHeader->nFilledLen = 0;
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+
+ mEOSStatus = OUTPUT_FRAMES_FLUSHED;
+}
+
+void SoftFFmpegVideo::drainAllOutputBuffers() {
+ List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+ if (!mCodecAlreadyOpened) {
+ drainEOSOutputBuffer();
+ mEOSStatus = OUTPUT_FRAMES_FLUSHED;
+ return;
+ }
+
+ if(!(mCtx->codec->capabilities & CODEC_CAP_DELAY)) {
+ drainEOSOutputBuffer();
+ mEOSStatus = OUTPUT_FRAMES_FLUSHED;
+ return;
+ }
+
+ while (!outQueue.empty()) {
+ if (!mPendingFrameAsSettingChanged) {
+ int32_t err = decodeVideo();
+ if (err < ERR_OK) {
notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
mSignalledError = true;
return;
+ } else if (err == ERR_FLUSHED) {
+ drainEOSOutputBuffer();
+ return;
+ } else {
+ CHECK_EQ(err, ERR_OK);
+ if (mPendingFrameAsSettingChanged) {
+ return;
+ }
}
- }
+ }
- int gotPic = false;
- AVFrame *frame = avcodec_alloc_frame();
- err = avcodec_decode_video2(mCtx, frame, &gotPic, &pkt);
- if (err < 0) {
- LOGE("ffmpeg video decoder failed to decode frame. (%d)", err);
+ if (drainOneOutputBuffer() != ERR_OK) {
notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
mSignalledError = true;
- av_free(frame);
return;
+ }
+
+ if (mPendingFrameAsSettingChanged) {
+ mPendingFrameAsSettingChanged = false;
}
+ }
+}
+
+void SoftFFmpegVideo::onQueueFilled(OMX_U32 portIndex) {
+ BufferInfo *inInfo = NULL;
+ OMX_BUFFERHEADERTYPE *inHeader = NULL;
+ List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
+ List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+
+ if (mSignalledError || mOutputPortSettingsChange != NONE) {
+ return;
+ }
+
+ if (mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
+ return;
+ }
- if (gotPic) {
- AVPicture pict;
- int64_t pts = AV_NOPTS_VALUE;
- uint8_t *dst = outHeader->pBuffer;
-
- memset(&pict, 0, sizeof(AVPicture));
- pict.data[0] = dst;
- pict.data[1] = dst + mStride * mHeight;
- pict.data[2] = pict.data[1] + (mStride / 2 * mHeight / 2);
- pict.linesize[0] = mStride;
- pict.linesize[1] = mStride / 2;
- pict.linesize[2] = mStride / 2;
-
- int sws_flags = SWS_BICUBIC;
- mImgConvertCtx = sws_getCachedContext(mImgConvertCtx,
- mWidth, mHeight, mCtx->pix_fmt, mWidth, mHeight,
- PIX_FMT_YUV420P, sws_flags, NULL, NULL, NULL);
- if (mImgConvertCtx == NULL) {
- LOGE("Cannot initialize the conversion context");
+ while (((mEOSStatus != INPUT_DATA_AVAILABLE) || !inQueue.empty())
+ && !outQueue.empty()) {
+ if (mEOSStatus == INPUT_EOS_SEEN) {
+ drainAllOutputBuffers();
+ return;
+ }
+
+ inInfo = *inQueue.begin();
+ inHeader = inInfo->mHeader;
+
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ ALOGD("ffmpeg video decoder empty eos inbuf");
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+ mEOSStatus = INPUT_EOS_SEEN;
+ continue;
+ }
+
+ if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
+ if (handleExtradata() != ERR_OK) {
notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
mSignalledError = true;
- av_free(frame);
- return;
- }
- sws_scale(mImgConvertCtx, frame->data, frame->linesize,
- 0, mHeight, pict.data, pict.linesize);
-
- outHeader->nOffset = 0;
- outHeader->nFilledLen = (mStride * mHeight * 3) / 2;
- outHeader->nFlags = 0;
- if (frame->key_frame)
- outHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
-
- // process timestamps
- if (decoder_reorder_pts == -1) {
- pts = *(int64_t*)av_opt_ptr(avcodec_get_frame_class(),
- frame, "best_effort_timestamp");
- } else if (decoder_reorder_pts) {
- pts = frame->pkt_pts;
- } else {
- pts = frame->pkt_dts;
}
+ continue;
+ }
- if (pts == AV_NOPTS_VALUE) {
- pts = 0;
+ if (!mCodecAlreadyOpened) {
+ if (openDecoder() != ERR_OK) {
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ return;
}
- outHeader->nTimeStamp = pts;
+ }
-#if DEBUG_FRM
- LOGV("frame pts: %lld", pts);
-#endif
+ if (!mPendingFrameAsSettingChanged) {
+ int32_t err = decodeVideo();
+ if (err < ERR_OK) {
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ return;
+ } else if (err == ERR_NO_FRM) {
+ continue;
+ } else {
+ CHECK_EQ(err, ERR_OK);
+ if (mPendingFrameAsSettingChanged) {
+ return;
+ }
+ }
+ }
- outInfo->mOwnedByUs = false;
- outQueue.erase(outQueue.begin());
- outInfo = NULL;
- notifyFillBufferDone(outHeader);
- outHeader = NULL;
+ if (drainOneOutputBuffer() != ERR_OK) {
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ return;
+ }
+
+ if (mPendingFrameAsSettingChanged) {
+ mPendingFrameAsSettingChanged = false;
}
-
- inInfo->mOwnedByUs = false;
- inQueue.erase(inQueue.begin());
- inInfo = NULL;
- notifyEmptyBufferDone(inHeader);
- inHeader = NULL;
- av_free(frame);
}
}
void SoftFFmpegVideo::onPortFlushCompleted(OMX_U32 portIndex) {
- if (portIndex == 0 && mCtx) {
- // Make sure that the next buffer output does not still
- // depend on fragments from the last one decoded.
- avcodec_flush_buffers(mCtx);
+ ALOGV("ffmpeg video decoder flush port(%lu)", portIndex);
+ if (portIndex == kInputPortIndex && mCtx) {
+ if (mCtx) {
+ //Make sure that the next buffer output does not still
+ //depend on fragments from the last one decoded.
+ avcodec_flush_buffers(mCtx);
+ }
+ mEOSStatus = INPUT_DATA_AVAILABLE;
}
}
void SoftFFmpegVideo::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
- if (portIndex != 1) {
+ if (portIndex != kOutputPortIndex) {
return;
}