Improvements from Stragus and leyyin

This commit is contained in:
Benau 2017-04-09 15:28:28 +08:00
parent 156b799011
commit a5759afac7
9 changed files with 130 additions and 77 deletions

View File

@ -612,32 +612,36 @@ void IrrDriver::initDevice()
cfg.m_height = m_actual_screen_size.Height;
int vf = UserConfigParams::m_record_format;
cfg.m_video_format = (VideoFormat)vf;
cfg.m_audio_format = REC_AF_VORBIS;
cfg.m_audio_format = OGR_AF_VORBIS;
cfg.m_audio_bitrate = 112000;
cfg.m_video_bitrate = UserConfigParams::m_vp_bitrate;
cfg.m_record_fps = UserConfigParams::m_record_fps;
cfg.m_record_jpg_quality = UserConfigParams::m_recorder_jpg_quality;
ogrInitConfig(&cfg);
if (ogrInitConfig(&cfg) == 0)
{
Log::error("irr_driver",
"RecorderConfig is invalid, use the default one.");
}
ogrRegGeneralCallback(REC_CBT_START_RECORDING,
ogrRegGeneralCallback(OGR_CBT_START_RECORDING,
[] (void* user_data) { MessageQueue::add
(MessageQueue::MT_GENERIC, _("Video recording started.")); }, NULL);
ogrRegGeneralCallback(REC_CBT_ERROR_RECORDING,
ogrRegGeneralCallback(OGR_CBT_ERROR_RECORDING,
[] (void* user_data) { MessageQueue::add
(MessageQueue::MT_ERROR, _("Error when saving video.")); }, NULL);
ogrRegGeneralCallback(REC_CBT_SLOW_RECORDING,
ogrRegGeneralCallback(OGR_CBT_SLOW_RECORDING,
[] (void* user_data) { MessageQueue::add
(MessageQueue::MT_ERROR, _("Encoding is too slow, dropping frames."));
}, NULL);
ogrRegGeneralCallback(REC_CBT_WAIT_RECORDING,
ogrRegGeneralCallback(OGR_CBT_WAIT_RECORDING,
[] (void* user_data) { MessageQueue::add
(MessageQueue::MT_GENERIC, _("Please wait while encoding is finished."
)); }, NULL);
ogrRegStringCallback(REC_CBT_SAVED_RECORDING,
ogrRegStringCallback(OGR_CBT_SAVED_RECORDING,
[] (const char* s, void* user_data) { MessageQueue::add
(MessageQueue::MT_GENERIC, _("Video saved in \"%s\".", s));
}, NULL);
ogrRegIntCallback(REC_CBT_PROGRESS_RECORDING,
ogrRegIntCallback(OGR_CBT_PROGRESS_RECORDING,
[] (const int i, void* user_data)
{ Log::info("Recorder", "%d%% of video encoding finished", i);}, NULL);

View File

@ -59,7 +59,7 @@ CaptureLibrary::~CaptureLibrary()
// ----------------------------------------------------------------------------
void CaptureLibrary::reset()
{
runCallback(REC_CBT_START_RECORDING, NULL);
runCallback(OGR_CBT_START_RECORDING, NULL);
m_pbo_use = 0;
m_accumulated_time = 0.;
assert(m_sound_stop.load() && ogrCapturing() == 0);
@ -71,14 +71,14 @@ void CaptureLibrary::reset()
setCapturing(true);
switch (m_recorder_cfg->m_video_format)
{
case REC_VF_VP8:
case REC_VF_VP9:
case OGR_VF_VP8:
case OGR_VF_VP9:
m_video_enc_thread = std::thread(Recorder::vpxEncoder, this);
break;
case REC_VF_MJPEG:
case OGR_VF_MJPEG:
m_video_enc_thread = std::thread(Recorder::mjpegWriter, this);
break;
case REC_VF_H264:
case OGR_VF_H264:
break;
}
} // reset
@ -221,7 +221,7 @@ void CaptureLibrary::captureConversion(CaptureLibrary* cl)
std::unique_lock<std::mutex> ulj(cl->m_jpg_list_mutex);
if (!cl->m_destroy.load() && cl->m_jpg_list.size() > 100)
{
runCallback(REC_CBT_WAIT_RECORDING, NULL);
runCallback(OGR_CBT_WAIT_RECORDING, NULL);
}
cl->m_display_progress.store(true);
cl->m_jpg_list.emplace_back((uint8_t*)NULL, 0, 0);
@ -237,11 +237,11 @@ void CaptureLibrary::captureConversion(CaptureLibrary* cl)
}
if (f.empty())
{
runCallback(REC_CBT_ERROR_RECORDING, NULL);
runCallback(OGR_CBT_ERROR_RECORDING, NULL);
}
else
{
runCallback(REC_CBT_SAVED_RECORDING, f.c_str());
runCallback(OGR_CBT_SAVED_RECORDING, f.c_str());
}
setCapturing(false);
continue;
@ -255,7 +255,7 @@ void CaptureLibrary::captureConversion(CaptureLibrary* cl)
const bool too_slow = cl->m_fbi_list.size() > 50;
if (too_slow)
{
runCallback(REC_CBT_SLOW_RECORDING, NULL);
runCallback(OGR_CBT_SLOW_RECORDING, NULL);
delete [] fbi;
cl->m_fbi_list.pop_front();
for (auto& p : cl->m_fbi_list)

View File

@ -35,7 +35,7 @@ namespace Recorder
std::string no_ext = video.substr(0, video.find_last_of("."));
VideoFormat vf = getConfig()->m_video_format;
std::string file_name = no_ext +
(vf == REC_VF_VP8 || vf == REC_VF_VP9 ? ".webm" : ".mkv");
(vf == OGR_VF_VP8 || vf == OGR_VF_VP9 ? ".webm" : ".mkv");
mkvmuxer::MkvWriter writer;
if (!writer.Open(file_name.c_str()))
{
@ -122,16 +122,16 @@ namespace Recorder
vt->set_frame_rate(getConfig()->m_record_fps);
switch (vf)
{
case REC_VF_VP8:
case OGR_VF_VP8:
vt->set_codec_id("V_VP8");
break;
case REC_VF_VP9:
case OGR_VF_VP9:
vt->set_codec_id("V_VP9");
break;
case REC_VF_MJPEG:
case OGR_VF_MJPEG:
vt->set_codec_id("V_MJPEG");
break;
case REC_VF_H264:
case OGR_VF_H264:
vt->set_codec_id("V_MPEG4/ISO/AVC");
break;
}
@ -154,7 +154,7 @@ namespace Recorder
}
muxer_frame.set_track_number(vid_track);
muxer_frame.set_timestamp(timestamp);
if (vf == REC_VF_VP8 || vf == REC_VF_VP9)
if (vf == OGR_VF_VP8 || vf == OGR_VF_VP9)
{
muxer_frame.set_is_key((flag & VPX_FRAME_IS_KEY) != 0);
}

View File

@ -6,21 +6,27 @@
* \mainpage libopenglrecorder
*
* libopenglrecorder is a library allowing (optional) async readback opengl
* framebuffer with audio recording. It will do video and audio encoding
* frame buffer with audio recording. It will do video and audio encoding
* together. The user of this library has to setup opengl context himself
* and load suitable callback. All function here should be called by the same
* thread which created the opengl context.
*/
/**
* List of audio encoder supported by libopenglrecorder.
* List of audio encoder supported by libopenglrecorder, if you want to record
* without sound, just set m_record_audio in \ref RecorderConfig to 0 and use
* any encoder below.
*/
enum AudioFormat
{
/**
* Vorbis encoder by libvorbisenc.
*/
REC_AF_VORBIS,
OGR_AF_VORBIS = 0,
/**
* Total numbers of audio encoder.
*/
OGR_AF_COUNT
};
/**
@ -31,19 +37,23 @@ enum VideoFormat
/**
* VP8 encoder by libvpx.
*/
REC_VF_VP8,
OGR_VF_VP8 = 0,
/**
* VP9 encoder by libvpx. Notice: this is very slow.
*/
REC_VF_VP9,
OGR_VF_VP9,
/**
* MJPEG encoder, it's provided by turbojpeg and will always present.
*/
REC_VF_MJPEG,
OGR_VF_MJPEG,
/**
* H264 encoder by openh264.
*/
REC_VF_H264
OGR_VF_H264,
/**
* Total numbers of video encoder.
*/
OGR_VF_COUNT
};
/**
@ -67,35 +77,35 @@ enum CallBackType
/**
* A \ref GeneralCallback which notify the starting of recording.
*/
REC_CBT_START_RECORDING = 0,
OGR_CBT_START_RECORDING = 0,
/**
* A \ref StringCallback which notify the saved filename of recorded file.
*/
REC_CBT_SAVED_RECORDING,
OGR_CBT_SAVED_RECORDING,
/**
* A \ref GeneralCallback which notify error when recording.
*/
REC_CBT_ERROR_RECORDING,
OGR_CBT_ERROR_RECORDING,
/**
* A \ref IntCallback which the tells the progress percentage for video
* encoding after the issue of \ref ogrStopCapture.
*/
REC_CBT_PROGRESS_RECORDING,
OGR_CBT_PROGRESS_RECORDING,
/**
* A \ref GeneralCallback which notify user if there is still video
* encoding happening after the issue of \ref ogrStopCapture.
*/
REC_CBT_WAIT_RECORDING,
OGR_CBT_WAIT_RECORDING,
/**
* A \ref GeneralCallback which notify user if the coversion to jpeg
* from opengl frame buffer image is too slow, so libopenglrecorder will
* drop frames.
*/
REC_CBT_SLOW_RECORDING,
OGR_CBT_SLOW_RECORDING,
/**
* Total callback numbers.
*/
REC_CBT_COUNT
OGR_CBT_COUNT
};
/**
@ -104,16 +114,16 @@ enum CallBackType
struct RecorderConfig
{
/**
* 1 if triple buffering is used when capture the opengl buffer.
* 1 if triple buffering is used when capture the opengl frame buffer.
* It will create 3 pixel buffer objects for async reading, recommend on.
* 0 otherwise.
*/
int m_triple_buffering;
unsigned int m_triple_buffering;
/**
* 1 if audio is recorded together, it will use wasapi in windows,
* pulseaudio in linux. 0 otherwise.
* pulseaudio in linux. 0 means no audio will be recorded.
*/
int m_record_audio;
unsigned int m_record_audio;
/**
* Width of the capture, it will be floored down to the closest integer divisble
* by 8 if needed.
@ -156,8 +166,10 @@ extern "C"
#endif
/**
* Initialize the configuration, call this first before using the library.
* \return 1 if succesfully configured, 0 otherwise and a default
* configuration will be used.
*/
void ogrInitConfig(RecorderConfig*);
int ogrInitConfig(RecorderConfig*);
/**
* Set the full path with filename for saving the recorded video, excluding
* extension, libopenglrecorder will automatically add .webm or .mkv as needed.

View File

@ -491,7 +491,7 @@ namespace Recorder
switch (cl->getRecorderConfig().m_audio_format)
{
case REC_AF_VORBIS:
case OGR_AF_VORBIS:
audio_enc_thread = std::thread(vorbisEncoder, &aed);
break;
}

View File

@ -29,11 +29,48 @@ GeneralCallback g_cb_error_rec = NULL;
// ============================================================================
GeneralCallback g_cb_slow_rec = NULL;
// ============================================================================
std::array<void*, REC_CBT_COUNT> g_all_user_data;
std::array<void*, OGR_CBT_COUNT> g_all_user_data;
// ============================================================================
void ogrInitConfig(RecorderConfig* rc)
bool validateConfig(RecorderConfig* rc)
{
if (rc == NULL)
return false;
if (rc->m_triple_buffering > 1 || rc->m_record_audio > 1)
return false;
if (rc->m_width > 16384 || rc->m_height > 16384)
return false;
if (rc->m_video_format >= OGR_VF_COUNT ||
rc->m_audio_format >= OGR_AF_COUNT)
return false;
if (rc->m_audio_bitrate == 0 || rc->m_video_bitrate == 0 ||
rc->m_record_fps == 0)
return false;
if (rc->m_record_jpg_quality > 100)
return false;
return true;
} // validateConfig
// ----------------------------------------------------------------------------
int ogrInitConfig(RecorderConfig* rc)
{
RecorderConfig* new_rc = new RecorderConfig;
g_recorder_config.reset(new_rc);
if (!validateConfig(rc))
{
new_rc->m_triple_buffering = 1;
new_rc->m_record_audio = 0;
new_rc->m_width = 800;
new_rc->m_height = 600;
new_rc->m_video_format = OGR_VF_MJPEG;
new_rc->m_audio_format = OGR_AF_VORBIS;
new_rc->m_audio_bitrate = 112000;
new_rc->m_video_bitrate = 100000;
new_rc->m_record_fps = 30;
new_rc->m_record_jpg_quality = 90;
return 0;
}
memcpy(new_rc, rc, sizeof(RecorderConfig));
while (new_rc->m_width % 8 != 0)
{
@ -43,7 +80,7 @@ void ogrInitConfig(RecorderConfig* rc)
{
new_rc->m_height--;
}
g_recorder_config.reset(new_rc);
return 1;
} // ogrInitConfig
// ----------------------------------------------------------------------------
@ -100,21 +137,21 @@ void ogrRegGeneralCallback(CallBackType cbt, GeneralCallback cb, void* data)
{
switch (cbt)
{
case REC_CBT_ERROR_RECORDING:
case OGR_CBT_ERROR_RECORDING:
g_cb_error_rec = cb;
g_all_user_data[REC_CBT_ERROR_RECORDING] = data;
g_all_user_data[OGR_CBT_ERROR_RECORDING] = data;
break;
case REC_CBT_START_RECORDING:
case OGR_CBT_START_RECORDING:
g_cb_start_rec = cb;
g_all_user_data[REC_CBT_START_RECORDING] = data;
g_all_user_data[OGR_CBT_START_RECORDING] = data;
break;
case REC_CBT_SLOW_RECORDING:
case OGR_CBT_SLOW_RECORDING:
g_cb_slow_rec = cb;
g_all_user_data[REC_CBT_SLOW_RECORDING] = data;
g_all_user_data[OGR_CBT_SLOW_RECORDING] = data;
break;
case REC_CBT_WAIT_RECORDING:
case OGR_CBT_WAIT_RECORDING:
g_cb_wait_rec = cb;
g_all_user_data[REC_CBT_WAIT_RECORDING] = data;
g_all_user_data[OGR_CBT_WAIT_RECORDING] = data;
break;
default:
assert(false && "Wrong callback enum");
@ -127,9 +164,9 @@ void ogrRegStringCallback(CallBackType cbt, StringCallback cb, void* data)
{
switch (cbt)
{
case REC_CBT_SAVED_RECORDING:
case OGR_CBT_SAVED_RECORDING:
g_cb_saved_rec = cb;
g_all_user_data[REC_CBT_SAVED_RECORDING] = data;
g_all_user_data[OGR_CBT_SAVED_RECORDING] = data;
break;
default:
assert(false && "Wrong callback enum");
@ -142,9 +179,9 @@ void ogrRegIntCallback(CallBackType cbt, IntCallback cb, void* data)
{
switch (cbt)
{
case REC_CBT_PROGRESS_RECORDING:
case OGR_CBT_PROGRESS_RECORDING:
g_cb_progress_rec = cb;
g_all_user_data[REC_CBT_PROGRESS_RECORDING] = data;
g_all_user_data[OGR_CBT_PROGRESS_RECORDING] = data;
break;
default:
assert(false && "Wrong callback enum");
@ -157,42 +194,42 @@ void runCallback(CallBackType cbt, const void* arg)
{
switch (cbt)
{
case REC_CBT_START_RECORDING:
case OGR_CBT_START_RECORDING:
{
if (g_cb_start_rec == NULL) return;
g_cb_start_rec(g_all_user_data[REC_CBT_START_RECORDING]);
g_cb_start_rec(g_all_user_data[OGR_CBT_START_RECORDING]);
break;
}
case REC_CBT_SAVED_RECORDING:
case OGR_CBT_SAVED_RECORDING:
{
if (g_cb_saved_rec == NULL) return;
const char* s = (const char*)arg;
g_cb_saved_rec(s, g_all_user_data[REC_CBT_SAVED_RECORDING]);
g_cb_saved_rec(s, g_all_user_data[OGR_CBT_SAVED_RECORDING]);
break;
}
case REC_CBT_ERROR_RECORDING:
case OGR_CBT_ERROR_RECORDING:
{
if (g_cb_error_rec == NULL) return;
g_cb_error_rec(g_all_user_data[REC_CBT_ERROR_RECORDING]);
g_cb_error_rec(g_all_user_data[OGR_CBT_ERROR_RECORDING]);
break;
}
case REC_CBT_PROGRESS_RECORDING:
case OGR_CBT_PROGRESS_RECORDING:
{
if (g_cb_progress_rec == NULL) return;
const int* i = (const int*)arg;
g_cb_progress_rec(*i, g_all_user_data[REC_CBT_PROGRESS_RECORDING]);
g_cb_progress_rec(*i, g_all_user_data[OGR_CBT_PROGRESS_RECORDING]);
break;
}
case REC_CBT_WAIT_RECORDING:
case OGR_CBT_WAIT_RECORDING:
{
if (g_cb_wait_rec == NULL) return;
g_cb_wait_rec(g_all_user_data[REC_CBT_WAIT_RECORDING]);
g_cb_wait_rec(g_all_user_data[OGR_CBT_WAIT_RECORDING]);
break;
}
case REC_CBT_SLOW_RECORDING:
case OGR_CBT_SLOW_RECORDING:
{
if (g_cb_slow_rec == NULL) return;
g_cb_slow_rec(g_all_user_data[REC_CBT_SLOW_RECORDING]);
g_cb_slow_rec(g_all_user_data[OGR_CBT_SLOW_RECORDING]);
break;
}
default:

View File

@ -39,7 +39,7 @@ namespace Recorder
vorbis_comment vc;
vorbis_comment_init(&vc);
vorbis_comment_add_tag(&vc, "Encoder",
"vorbis encoder by libopenglrecorder");
"Vorbis encoder by libopenglrecorder");
ogg_packet header;
ogg_packet header_comm;
ogg_packet header_code;

View File

@ -69,14 +69,14 @@ namespace Recorder
vpx_codec_iface_t* codec_if = NULL;
switch (cl->getRecorderConfig().m_video_format)
{
case REC_VF_VP8:
case OGR_VF_VP8:
codec_if = vpx_codec_vp8_cx();
break;
case REC_VF_VP9:
case OGR_VF_VP9:
codec_if = vpx_codec_vp9_cx();
break;
case REC_VF_MJPEG:
case REC_VF_H264:
case OGR_VF_MJPEG:
case OGR_VF_H264:
assert(false);
break;
}
@ -128,7 +128,7 @@ namespace Recorder
last_size = (float)(cl->getJPGList()->size());
cur_finished_count += frame_count;
int rate = (int)(cur_finished_count / last_size * 100.0f);
runCallback(REC_CBT_PROGRESS_RECORDING, &rate);
runCallback(OGR_CBT_PROGRESS_RECORDING, &rate);
}
uint8_t* yuv = NULL;
unsigned yuv_size;

View File

@ -224,7 +224,7 @@ namespace Recorder
switch (cl->getRecorderConfig().m_audio_format)
{
case REC_AF_VORBIS:
case OGR_AF_VORBIS:
audio_enc_thread = std::thread(vorbisEncoder, &aed);
break;
}