Skip to content

Instantly share code, notes, and snippets.

@fantasyRqg
Created July 22, 2017 07:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fantasyRqg/c8cfbdf3a21c22d6d324b2d14c1db1a7 to your computer and use it in GitHub Desktop.
Save fantasyRqg/c8cfbdf3a21c22d6d324b2d14c1db1a7 to your computer and use it in GitHub Desktop.
//
// 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