From 294aa3ad488a5741141f2a844183cc45c2db9959 Mon Sep 17 00:00:00 2001 From: Benau Date: Sat, 1 Apr 2017 11:02:14 +0800 Subject: [PATCH] Allow recording 16bit pcm data with any channels --- .../{vorbis_encode.cpp => vorbis_encoder.cpp} | 26 ++-- .../{vorbis_encode.hpp => vorbis_encoder.hpp} | 0 src/recorder/wasapi_record.cpp | 39 +++--- src/utils/avi_writer.cpp | 122 ++---------------- src/utils/avi_writer.hpp | 2 - 5 files changed, 44 insertions(+), 145 deletions(-) rename src/recorder/{vorbis_encode.cpp => vorbis_encoder.cpp} (86%) rename src/recorder/{vorbis_encode.hpp => vorbis_encoder.hpp} (100%) diff --git a/src/recorder/vorbis_encode.cpp b/src/recorder/vorbis_encoder.cpp similarity index 86% rename from src/recorder/vorbis_encode.cpp rename to src/recorder/vorbis_encoder.cpp index a4c989fc4..c717669c9 100644 --- a/src/recorder/vorbis_encode.cpp +++ b/src/recorder/vorbis_encoder.cpp @@ -17,7 +17,7 @@ #if !(defined(SERVER_ONLY) || defined(USE_GLES2)) -#include "recorder/vorbis_encode.hpp" +#include "recorder/vorbis_encoder.hpp" #include "utils/avi_writer.hpp" #include "utils/log.hpp" #include "utils/vs.hpp" @@ -79,7 +79,6 @@ namespace Recorder pthread_cond_t* cond_request = ved->m_enc_request; ogg_packet op; int64_t last_timestamp = 0; - const unsigned channels = ved->m_channels; while (true) { audio_data->lock(); @@ -92,7 +91,6 @@ namespace Recorder int8_t* audio_buf = audio_data->getData().front(); audio_data->getData().pop_front(); audio_data->unlock(); - long i = 0; if (audio_buf == NULL) { break; @@ -100,28 +98,32 @@ namespace Recorder else { float **buffer = vorbis_analysis_buffer(&vd, 1024); + const unsigned channels = ved->m_channels; if (ved->m_audio_type == VorbisEncoderData::AT_PCM) { - for (i = 0; i < 1024; i++) + for (unsigned j = 0; j < channels; j++) { - buffer[0][i] = ((audio_buf[i * 4 + 1] << 8) | - (0x00ff & (int)audio_buf[i * 4])) / 32768.0f; - buffer[1][i] = ((audio_buf[i * 4 + 3] << 8) | - (0x00ff & (int)audio_buf[i * 4 + 2])) / 32768.0f; + for (unsigned i = 0; i < 1024; i++) + { + int8_t* each_channel = + &audio_buf[i * channels * 2 + j * 2]; + buffer[j][i] = float((each_channel[1] << 8) | + (0x00ff & (int)each_channel[0])) / 32768.0f; + } } } else { - float* float_buf = reinterpret_cast(audio_buf); for (unsigned j = 0; j < channels; j++) { - for (i = 0; i < 1024; i++) + for (unsigned i = 0; i < 1024; i++) { - buffer[j][i] = float_buf[i * channels + j]; + float* fbuf = reinterpret_cast(audio_buf); + buffer[j][i] = fbuf[i * channels + j]; } } } - vorbis_analysis_wrote(&vd, i); + vorbis_analysis_wrote(&vd, 1024); } while (vorbis_analysis_blockout(&vd, &vb) == 1) { diff --git a/src/recorder/vorbis_encode.hpp b/src/recorder/vorbis_encoder.hpp similarity index 100% rename from src/recorder/vorbis_encode.hpp rename to src/recorder/vorbis_encoder.hpp diff --git a/src/recorder/wasapi_record.cpp b/src/recorder/wasapi_record.cpp index bb910cf1c..3b2dcc409 100644 --- a/src/recorder/wasapi_record.cpp +++ b/src/recorder/wasapi_record.cpp @@ -17,7 +17,7 @@ #if !(defined(SERVER_ONLY) || defined(USE_GLES2)) && defined(WIN32) -#include "recorder/vorbis_encode.hpp" +#include "recorder/vorbis_encoder.hpp" #include "utils/synchronised.hpp" #include "utils/log.hpp" #include "utils/vs.hpp" @@ -44,6 +44,7 @@ namespace Recorder IAudioCaptureClient* m_capture_client; WAVEFORMATEX* m_wav_format; uint32_t m_buffer_size; + // -------------------------------------------------------------------- WasapiData() { m_loaded = false; @@ -53,6 +54,7 @@ namespace Recorder m_capture_client = NULL; m_wav_format = NULL; } // WasapiData + // -------------------------------------------------------------------- bool load() { HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, @@ -93,6 +95,7 @@ namespace Recorder m_loaded = true; return true; } // load + // -------------------------------------------------------------------- ~WasapiData() { if (m_loaded) @@ -180,25 +183,25 @@ namespace Recorder ->nSamplesPerSec; Synchronised* idle = (Synchronised*)obj; - Synchronised > pcm_data; + Synchronised > audio_data; pthread_cond_t enc_request; pthread_cond_init(&enc_request, NULL); pthread_t vorbis_enc; - ved.m_data = &pcm_data; + ved.m_data = &audio_data; ved.m_enc_request = &enc_request; pthread_create(&vorbis_enc, NULL, &Recorder::vorbisEncoder, &ved); const unsigned frag_size = 1024 * ved.m_channels * (g_wasapi_data.m_wav_format->wBitsPerSample / 8); - int8_t* each_pcm_buf = new int8_t[frag_size](); + int8_t* each_audio_buf = new int8_t[frag_size](); unsigned readed = 0; while (true) { if (idle->getAtomic()) { - pcm_data.lock(); - pcm_data.getData().push_back(each_pcm_buf); + audio_data.lock(); + audio_data.getData().push_back(each_audio_buf); pthread_cond_signal(&enc_request); - pcm_data.unlock(); + audio_data.unlock(); break; } REFERENCE_TIME sleep_time = duration / 10000 / 2; @@ -224,25 +227,25 @@ namespace Recorder unsigned copy_size = buf_full ? frag_size - readed : bytes; if (!(flags & AUDCLNT_BUFFERFLAGS_SILENT)) { - memcpy(each_pcm_buf + readed, data, copy_size); + memcpy(each_audio_buf + readed, data, copy_size); } if (buf_full) { - pcm_data.lock(); - pcm_data.getData().push_back(each_pcm_buf); + audio_data.lock(); + audio_data.getData().push_back(each_audio_buf); pthread_cond_signal(&enc_request); - pcm_data.unlock(); - each_pcm_buf = new int8_t[frag_size](); - readed = (unsigned)bytes - copy_size; + audio_data.unlock(); + each_audio_buf = new int8_t[frag_size](); + readed = bytes - copy_size; if (!(flags & AUDCLNT_BUFFERFLAGS_SILENT)) { - memcpy(each_pcm_buf, (uint8_t*)data + copy_size, + memcpy(each_audio_buf, (uint8_t*)data + copy_size, readed); } } else { - readed += (unsigned)bytes; + readed += bytes; } hr = g_wasapi_data.m_capture_client->ReleaseBuffer(frame_size); if (FAILED(hr)) @@ -257,10 +260,10 @@ namespace Recorder return NULL; } } - pcm_data.lock(); - pcm_data.getData().push_back(NULL); + audio_data.lock(); + audio_data.getData().push_back(NULL); pthread_cond_signal(&enc_request); - pcm_data.unlock(); + audio_data.unlock(); pthread_join(vorbis_enc, NULL); pthread_cond_destroy(&enc_request); diff --git a/src/utils/avi_writer.cpp b/src/utils/avi_writer.cpp index 4f0b029dc..5f9bf9249 100644 --- a/src/utils/avi_writer.cpp +++ b/src/utils/avi_writer.cpp @@ -22,6 +22,7 @@ #include "config/user_config.hpp" #include "graphics/irr_driver.hpp" #include "guiengine/message_queue.hpp" +#include "recorder/vorbis_encoder.hpp" #include "recorder/webm_writer.hpp" #include "utils/translation.hpp" #include "utils/vs.hpp" @@ -34,7 +35,6 @@ #endif #include -#include #include #include @@ -377,113 +377,6 @@ void* AVIWriter::videoRecord(void *obj) return NULL; } // videoRecord -// ---------------------------------------------------------------------------- -void* AVIWriter::vorbisEncoder(void *obj) -{ - VS::setThreadName("vorbisEncoder"); - vorbis_info vi; - vorbis_dsp_state vd; - vorbis_block vb; - vorbis_info_init(&vi); - vorbis_encode_init(&vi, 2, 44100, -1, 112000, -1); - vorbis_analysis_init(&vd, &vi); - vorbis_block_init(&vd, &vb); - vorbis_comment vc; - vorbis_comment_init(&vc); - vorbis_comment_add_tag(&vc, "ENCODER", "STK vorbis encoder"); - ogg_packet header; - ogg_packet header_comm; - ogg_packet header_code; - vorbis_analysis_headerout(&vd, &vc, &header, &header_comm, &header_code); - if (header.bytes > 255 || header_comm.bytes > 255) - { - Log::error("vorbisEncoder", "Header is too long."); - return NULL; - } - FILE* vb_data = fopen((m_recording_target.getAtomic() + ".vb_data") - .c_str(), "wb"); - if (vb_data == NULL) - { - Log::error("vorbisEncoder", "Failed to open file for encoding vorbis."); - return NULL; - } - const uint32_t all = header.bytes + header_comm.bytes + header_code.bytes - + 3; - fwrite(&all, 1, sizeof(uint32_t), vb_data); - fwrite(&all, 1, sizeof(uint32_t), vb_data); - fwrite(&all, 1, sizeof(uint32_t), vb_data); - uint8_t size = 2; - fwrite(&size, 1, sizeof(uint8_t), vb_data); - size = (uint8_t)header.bytes; - fwrite(&size, 1, sizeof(uint8_t), vb_data); - size = (uint8_t)header_comm.bytes; - fwrite(&size, 1, sizeof(uint8_t), vb_data); - fwrite(header.packet, 1, header.bytes, vb_data); - fwrite(header_comm.packet, 1, header_comm.bytes, vb_data); - fwrite(header_code.packet, 1, header_code.bytes, vb_data); - EncoderInfo* ei = (EncoderInfo*)obj; - Synchronised >* pcm_data = - (Synchronised >*)ei->m_data; - pthread_cond_t* cond_request = ei->m_enc_request; - ogg_packet op; - int64_t last_timestamp = 0; - while (true) - { - pcm_data->lock(); - bool waiting = pcm_data->getData().empty(); - while (waiting) - { - pthread_cond_wait(cond_request, pcm_data->getMutex()); - waiting = pcm_data->getData().empty(); - } - const int8_t* pcm_buf = pcm_data->getData().front(); - pcm_data->getData().pop_front(); - pcm_data->unlock(); - long i = 0; - if (pcm_buf == NULL) - { - break; - } - else - { - float **buffer = vorbis_analysis_buffer(&vd, 1024); - for (i = 0; i < 1024; i++) - { - buffer[0][i] = ((pcm_buf[i * 4 + 1] << 8) | - (0x00ff & (int)pcm_buf[i * 4])) / 32768.0f; - buffer[1][i] = ((pcm_buf[i * 4 + 3] << 8) | - (0x00ff & (int)pcm_buf[i * 4 + 2])) / 32768.0f; - } - vorbis_analysis_wrote(&vd, i); - } - while (vorbis_analysis_blockout(&vd, &vb) == 1) - { - vorbis_analysis(&vb, NULL); - vorbis_bitrate_addblock(&vb); - while (vorbis_bitrate_flushpacket(&vd, &op)) - { - if (op.granulepos > 0) - { - uint32_t frame_size = (uint32_t)op.bytes; - fwrite(&frame_size, 1, sizeof(uint32_t), vb_data); - fwrite(&last_timestamp, 1, sizeof(int64_t), vb_data); - fwrite(op.packet, 1, frame_size, vb_data); - double s = (double)op.granulepos / 44100. * 1000000000.; - last_timestamp = (int64_t)s; - } - } - } - delete [] pcm_buf; - } - vorbis_block_clear(&vb); - vorbis_dsp_clear(&vd); - vorbis_comment_clear(&vc); - vorbis_info_clear(&vi); - fclose(vb_data); - return NULL; - -} // vorbisEncoder - #ifndef WIN32 // ---------------------------------------------------------------------------- void serverInfoCallBack(pa_context* c, const pa_server_info* i, void* data) @@ -532,7 +425,7 @@ void* AVIWriter::audioRecord(void *obj) sam_spec.channels = 2; pa_buffer_attr buf_attr; - const unsigned frag_size = 1024 * 2 * sizeof(int16_t); + const unsigned frag_size = 1024 * sam_spec.channels * sizeof(int16_t); buf_attr.fragsize = frag_size; const unsigned max_uint = -1; buf_attr.maxlength = max_uint; @@ -564,10 +457,13 @@ void* AVIWriter::audioRecord(void *obj) pthread_cond_init(&enc_request, NULL); pthread_t vorbis_enc_thread; - EncoderInfo ei; - ei.m_data = &pcm_data; - ei.m_enc_request = &enc_request; - pthread_create(&vorbis_enc_thread, NULL, &vorbisEncoder, &ei); + Recorder::VorbisEncoderData ved; + ved.m_sample_rate = sam_spec.rate; + ved.m_channels = sam_spec.channels; + ved.m_audio_type = Recorder::VorbisEncoderData::AT_PCM; + ved.m_data = &pcm_data; + ved.m_enc_request = &enc_request; + pthread_create(&vorbis_enc_thread, NULL, &Recorder::vorbisEncoder, &ved); int8_t* each_pcm_buf = new int8_t[frag_size](); unsigned readed = 0; while (true) diff --git a/src/utils/avi_writer.hpp b/src/utils/avi_writer.hpp index d1f3cdc9e..d6c4756e0 100644 --- a/src/utils/avi_writer.hpp +++ b/src/utils/avi_writer.hpp @@ -246,8 +246,6 @@ public: // ------------------------------------------------------------------------ static void* audioRecord(void *obj); // ------------------------------------------------------------------------ - static void* vorbisEncoder(void *obj); - // ------------------------------------------------------------------------ static void* vpxEncoder(void *obj); // ------------------------------------------------------------------------ static void setRecordingTarget(const std::string& name)