Created
July 22, 2017 07:51
-
-
Save fantasyRqg/c8cfbdf3a21c22d6d324b2d14c1db1a7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Created by ranqingguo on 7/21/17. | |
// | |
#include <cstdio> | |
#include "ExportThread.h" | |
#include "util/common.h" | |
#include "Player.h" | |
#define TAG "ExportThread" | |
enum { | |
kWhatDequeueFrame, | |
kWhatStart, | |
kWhatStop, | |
kWhatSetExportParams, | |
kWhatSignalEndOfStream, | |
}; | |
void ExportThread::handle(int what, void *data) { | |
switch (what) { | |
case kWhatDequeueFrame: | |
handleDequeueFrame(); | |
break; | |
case kWhatStart: | |
handleStart(); | |
break; | |
case kWhatStop: | |
handleStop(); | |
break; | |
case kWhatSetExportParams: | |
handleSetParams((ExportOpts *) data); | |
case kWhatSignalEndOfStream: { | |
AMediaCodec_signalEndOfInputStream(mEncoder); | |
} | |
break; | |
default: | |
break; | |
} | |
} | |
ExportThread::ExportThread(Painter *painter) | |
: Looper("export"), mPainter(painter) { | |
post(kWhatStart, nullptr); | |
} | |
ExportThread::~ExportThread() { | |
} | |
void ExportThread::handleStart() { | |
} | |
void ExportThread::handleStop() { | |
if (mEncoder != nullptr) { | |
AMediaCodec_stop(mEncoder); | |
AMediaCodec_delete(mEncoder); | |
mEncoder = nullptr; | |
} | |
if (mMuxer != nullptr) { | |
AMediaMuxer_stop(mMuxer); | |
AMediaMuxer_delete(mMuxer); | |
mMuxer = nullptr; | |
} | |
if (mOutFile != nullptr) { | |
fflush(mOutFile); | |
fclose(mOutFile); | |
mOutFile = nullptr; | |
} | |
mPainter->postExportFinished(); | |
} | |
void ExportThread::handleSetParams(ExportOpts *pOpts) { | |
#define COLOR_FormatSurface 0x7F000789 | |
FILE *file = fopen(pOpts->outPath.c_str(), "w"); | |
mOutFile = file; | |
int fd = fileno(file); | |
mMuxer = AMediaMuxer_new(fd, AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4); | |
char mime[] = "video/avc"; | |
AMediaFormat *format = AMediaFormat_new(); | |
AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, mime); | |
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, pOpts->width); | |
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, pOpts->height); | |
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, pOpts->bitrate); | |
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, pOpts->frameRate); | |
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, COLOR_FormatSurface); | |
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, 1); | |
mEncoder = AMediaCodec_createEncoderByType(mime); | |
if (mEncoder == nullptr) { | |
LOGE("AMediaCodec_createEncoderByType fail"); | |
} | |
auto r = AMediaCodec_configure(mEncoder, format, nullptr, nullptr, | |
AMEDIACODEC_CONFIGURE_FLAG_ENCODE); | |
if (r != AMEDIA_OK) { | |
LOGE("AMediaCodec_configure fail"); | |
} | |
ANativeWindow *window; | |
r = AMediaCodec_createInputSurface(mEncoder, &window); | |
if (r != AMEDIA_OK) { | |
LOGE("AMediaCodec_createInputSurface fail"); | |
} | |
r = AMediaCodec_start(mEncoder); | |
if (r != AMEDIA_OK) { | |
LOGE("AMediaCodec_start fail"); | |
} | |
mPainter->postCreateWindowSurface(window); | |
} | |
#define DEQUEUE_WAIT_TIME_US 0 | |
void ExportThread::handleDequeueFrame() { | |
auto index = AMediaCodec_dequeueOutputBuffer(mEncoder, &mInfo, DEQUEUE_WAIT_TIME_US); | |
switch (index) { | |
case AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED: { | |
auto format = AMediaCodec_getOutputFormat(mEncoder); | |
mVideoTrack = (size_t) AMediaMuxer_addTrack(mMuxer, format); | |
auto r = AMediaMuxer_start(mMuxer); | |
if (r != AMEDIA_OK) { | |
LOGE("AMediaMuxer_start fail"); | |
} | |
break; | |
} | |
case AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED: | |
break; | |
case AMEDIACODEC_INFO_TRY_AGAIN_LATER: | |
break; | |
default: { | |
size_t size = 0; | |
auto buf = AMediaCodec_getOutputBuffer(mEncoder, (size_t) index, &size); | |
if (mInfo.size > 0) { | |
auto r = AMediaMuxer_writeSampleData(mMuxer, mVideoTrack, buf, &mInfo); | |
if (r != AMEDIA_OK) { | |
LOGE("AMediaMuxer_writeSampleData fail"); | |
} | |
} | |
AMediaCodec_releaseOutputBuffer(mEncoder, (size_t) index, false); | |
if ((mInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) != 0) { | |
post(kWhatStop, nullptr); | |
return; | |
} | |
break; | |
} | |
} | |
post(kWhatDequeueFrame, nullptr); | |
} | |
void ExportThread::postSetup(ExportOpts *pOpts) { | |
post(kWhatSetExportParams, pOpts); | |
} | |
void ExportThread::signalEndOfStream() { | |
post(kWhatSignalEndOfStream, nullptr); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment