Я получаю поток H.264 от RTMP, но битрейт очень большой, я хочу перекодировать поток, чтобы уменьшить битрейт. Я создаю кодировщик с помощью createEncoderByType, после создания кодировщика я создаю поверхность из кодировщика с помощью createInputSurface. Затем я создаю декодер с кодировщиком формы поверхности, он работает нормально, но я не могу получить данные кодирования от кодера, он всегда возвращает -1000. Код следующий:
// config encoder
mEncode = AMediaCodec_createEncoderByType(MIME_TYPE);
if(mEncode == NULL) {
MW_LOGE("Encoder MediaCodecH264: could not create Encoder");
return false;
}
AMediaFormat *format = AMediaFormat_new();
AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, MIME_TYPE);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, ENCODE_WIDTH);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, ENCODE_HEIGHT);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, BIT_RATE);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, FRAME_RATE);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT,
0x7F000789 /*COLOR_FormatSurface, COLOR_FormatYUV420Flexible 21*/);
media_status_t status =
AMediaCodec_configure(mEncode, format, NULL, NULL, AMEDIACODEC_CONFIGURE_FLAG_ENCODE);
if(status != AMEDIA_OK) {
MW_LOGE("Encoder AMediaCodec_configure() failed with error %i for format %u", (int) status,
21);
AMediaFormat_delete(format);
AMediaCodec_delete(mEncode);
return false;
}
AMediaFormat_delete(format);
status = AMediaCodec_createInputSurface(mEncode, &surface);
if(status != AMEDIA_OK) {
MW_LOGE("Encoder AMediaCodec_createInputSurface() failed with error %i", (int) status);
AMediaCodec_delete(mEncode);
return false;
}
if((status = AMediaCodec_start(mEncode)) != AMEDIA_OK) {
MW_LOGE("Encoder AMediaCodec_start: Could not start encoder.");
AMediaCodec_delete(mEncode);
return false;
}
// config decoder
mDecode = AMediaCodec_createDecoderByType(MIME_TYPE);
if(nullptr == mDecode) {
MW_LOGE("cannot create decoder.");
return false;
}
AMediaFormat *format = AMediaFormat_new();
AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, MIME_TYPE);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, ENCODE_WIDTH);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, ENCODE_HEIGHT);
// AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, FRAME_RATE);
// for send a buf to codec at least
// AMediaFormat_setBuffer(format, "csd-0", sps, sizeof(sps)); // sps
// AMediaFormat_setBuffer(format, "csd-1", pps, sizeof(pps)); // pps
media_status_t status = AMediaCodec_configure(mDecode, format, surface, NULL, 0);
if(status != AMEDIA_OK) {
MW_LOGE("Decoder AMediaCodec_configure error.");
AMediaCodec_delete(mDecode);
mDecode = NULL;
AMediaFormat_delete(format);
return false;
}
AMediaFormat_delete(format);
status = AMediaCodec_start(mDecode);
if(status != AMEDIA_OK) {
MW_LOGE("Decoder AMediaCodec_start error.");
AMediaCodec_delete(mDecode);
mDecode = NULL;
return false;
}
// process data here
while(false == isConsumed) {
ssize_t bufidx = AMediaCodec_dequeueInputBuffer(mDecode, CODEC_TIMEOUT * 10);
if(bufidx >= 0) {
size_t bufsize;
uint8_t *codecBuf = AMediaCodec_getInputBuffer(mDecode, bufidx, &bufsize);
if(codecBuf == nullptr) {
MW_LOGE("AMediaCodec_getInputBuffer returned nullptr, short decode");
break;
}
if(buf->mDataSize > bufsize || nullptr == buf->mData) {
MW_LOGE("BufferItem info error. bufId:%d size:%d prt:%p", buf->mBufId,
buf->mDataSize, buf->mData);
break;
}
// std::string data = std::string((char *) buf->mData, 20);
// for(int i = 0; i < data.length(); i++) MW_LOGE(" 0x%x", data.at(i));
int size = buf->mDataSize;
if(mFirstDecode || buf->mConfigChanged) {
mFirstDecode = false;
memcpy(codecBuf, buf->mSPS.c_str(), buf->mSPS.size());
codecBuf += buf->mSPS.size();
memcpy(codecBuf, buf->mPPS.c_str(), buf->mPPS.size());
codecBuf += buf->mPPS.size();
size += buf->mSPS.size() + buf->mPPS.size();
}
memcpy(codecBuf, buf->mData, buf->mDataSize);
media_status_t mstatus =
AMediaCodec_queueInputBuffer(mDecode, bufidx, 0 /* offset */, size, 0, 0);
if(mstatus != AMEDIA_OK) {
// AMEDIA_ERROR_UNKNOWN == { -ERANGE -EINVAL -EACCES }
MW_LOGE("AMediaCodec_queueInputBuffer returned status %d, short decode",
(int) mstatus);
break;
}
isConsumed = true;
ret = true;
}
AMediaCodecBufferInfo info;
static long nFrameCount = 0;
MW_LOGD("start AMediaCodec_dequeueOutputBuffer");
status = AMediaCodec_dequeueOutputBuffer(mEncode, &info, 5000);
MW_LOGD("end AMediaCodec_dequeueOutputBuffer end!");
if(status >= 0) {
MW_LOGD("got encoded buffer[%d] of size=%d @%lld us flags=%x", nFrameCount, info.size,
(long long) info.presentationTimeUs, info.flags);
// mStats.add(info);
AMediaCodec_releaseOutputBuffer(mEncode, status, false);
++nFrameCount;
if(info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
MW_LOGD("saw EOS");
break;
}
} else if(status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
} else if(status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
std::shared_ptr<AMediaFormat> format = std::shared_ptr<AMediaFormat>(
AMediaCodec_getOutputFormat(mEncode), deleter_AMediaFormat);
// mStats.setOutputFormat(format);
MW_LOGD("format changed: %s", AMediaFormat_toString(format.get()));
} else if(status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
} else {
MW_LOGD("Invalid status : %d", status);
}
// AMediaCodecBufferInfo info;
// Get the index of the next available buffer of processed data. Donnot wait.
status = AMediaCodec_dequeueOutputBuffer(mDecode, &info, 0);
if(status >= 0) {
if(info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
MW_LOGE("output EOS");
break;
}
bool doRender = (info.size != 0);
media_status_t mstatus = AMediaCodec_releaseOutputBuffer(mDecode, status, doRender);
if(mstatus != AMEDIA_OK) {
// AMEDIA_ERROR_UNKNOWN == { -ERANGE -EINVAL -EACCES }
MW_LOGE("AMediaCodec_releaseOutputBuffer returned status %d, short decode",
(int) mstatus);
break;
}
MW_LOGD("AMediaCodec_releaseOutputBuffer bufidx:%d", status);
} else if(status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
MW_LOGD("output buffers changed");
} else if(status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
AMediaFormat *format = AMediaFormat_new();
format = AMediaCodec_getOutputFormat(mDecode);
MW_LOGD("format changed to: %s", AMediaFormat_toString(format));
AMediaFormat_delete(format);
} else if(status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
MW_LOGD("no output buffer right now");
} else if(status <= AMEDIA_ERROR_BASE) {
MW_LOGD("decode error: %d", status);
mDecodeErrorNum = status;
break;
} else {
MW_LOGD("unexpected info code: %d", status);
}
usleep(1000 * 10);
}