Allow recording 16bit pcm data with any channels
This commit is contained in:
parent
cacbdbd668
commit
294aa3ad48
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#if !(defined(SERVER_ONLY) || defined(USE_GLES2))
|
#if !(defined(SERVER_ONLY) || defined(USE_GLES2))
|
||||||
|
|
||||||
#include "recorder/vorbis_encode.hpp"
|
#include "recorder/vorbis_encoder.hpp"
|
||||||
#include "utils/avi_writer.hpp"
|
#include "utils/avi_writer.hpp"
|
||||||
#include "utils/log.hpp"
|
#include "utils/log.hpp"
|
||||||
#include "utils/vs.hpp"
|
#include "utils/vs.hpp"
|
||||||
@ -79,7 +79,6 @@ namespace Recorder
|
|||||||
pthread_cond_t* cond_request = ved->m_enc_request;
|
pthread_cond_t* cond_request = ved->m_enc_request;
|
||||||
ogg_packet op;
|
ogg_packet op;
|
||||||
int64_t last_timestamp = 0;
|
int64_t last_timestamp = 0;
|
||||||
const unsigned channels = ved->m_channels;
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
audio_data->lock();
|
audio_data->lock();
|
||||||
@ -92,7 +91,6 @@ namespace Recorder
|
|||||||
int8_t* audio_buf = audio_data->getData().front();
|
int8_t* audio_buf = audio_data->getData().front();
|
||||||
audio_data->getData().pop_front();
|
audio_data->getData().pop_front();
|
||||||
audio_data->unlock();
|
audio_data->unlock();
|
||||||
long i = 0;
|
|
||||||
if (audio_buf == NULL)
|
if (audio_buf == NULL)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@ -100,28 +98,32 @@ namespace Recorder
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
float **buffer = vorbis_analysis_buffer(&vd, 1024);
|
float **buffer = vorbis_analysis_buffer(&vd, 1024);
|
||||||
|
const unsigned channels = ved->m_channels;
|
||||||
if (ved->m_audio_type == VorbisEncoderData::AT_PCM)
|
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) |
|
for (unsigned i = 0; i < 1024; i++)
|
||||||
(0x00ff & (int)audio_buf[i * 4])) / 32768.0f;
|
{
|
||||||
buffer[1][i] = ((audio_buf[i * 4 + 3] << 8) |
|
int8_t* each_channel =
|
||||||
(0x00ff & (int)audio_buf[i * 4 + 2])) / 32768.0f;
|
&audio_buf[i * channels * 2 + j * 2];
|
||||||
|
buffer[j][i] = float((each_channel[1] << 8) |
|
||||||
|
(0x00ff & (int)each_channel[0])) / 32768.0f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float* float_buf = reinterpret_cast<float*>(audio_buf);
|
|
||||||
for (unsigned j = 0; j < channels; j++)
|
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<float*>(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)
|
while (vorbis_analysis_blockout(&vd, &vb) == 1)
|
||||||
{
|
{
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#if !(defined(SERVER_ONLY) || defined(USE_GLES2)) && defined(WIN32)
|
#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/synchronised.hpp"
|
||||||
#include "utils/log.hpp"
|
#include "utils/log.hpp"
|
||||||
#include "utils/vs.hpp"
|
#include "utils/vs.hpp"
|
||||||
@ -44,6 +44,7 @@ namespace Recorder
|
|||||||
IAudioCaptureClient* m_capture_client;
|
IAudioCaptureClient* m_capture_client;
|
||||||
WAVEFORMATEX* m_wav_format;
|
WAVEFORMATEX* m_wav_format;
|
||||||
uint32_t m_buffer_size;
|
uint32_t m_buffer_size;
|
||||||
|
// --------------------------------------------------------------------
|
||||||
WasapiData()
|
WasapiData()
|
||||||
{
|
{
|
||||||
m_loaded = false;
|
m_loaded = false;
|
||||||
@ -53,6 +54,7 @@ namespace Recorder
|
|||||||
m_capture_client = NULL;
|
m_capture_client = NULL;
|
||||||
m_wav_format = NULL;
|
m_wav_format = NULL;
|
||||||
} // WasapiData
|
} // WasapiData
|
||||||
|
// --------------------------------------------------------------------
|
||||||
bool load()
|
bool load()
|
||||||
{
|
{
|
||||||
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL,
|
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL,
|
||||||
@ -93,6 +95,7 @@ namespace Recorder
|
|||||||
m_loaded = true;
|
m_loaded = true;
|
||||||
return true;
|
return true;
|
||||||
} // load
|
} // load
|
||||||
|
// --------------------------------------------------------------------
|
||||||
~WasapiData()
|
~WasapiData()
|
||||||
{
|
{
|
||||||
if (m_loaded)
|
if (m_loaded)
|
||||||
@ -180,25 +183,25 @@ namespace Recorder
|
|||||||
->nSamplesPerSec;
|
->nSamplesPerSec;
|
||||||
|
|
||||||
Synchronised<bool>* idle = (Synchronised<bool>*)obj;
|
Synchronised<bool>* idle = (Synchronised<bool>*)obj;
|
||||||
Synchronised<std::list<int8_t*> > pcm_data;
|
Synchronised<std::list<int8_t*> > audio_data;
|
||||||
pthread_cond_t enc_request;
|
pthread_cond_t enc_request;
|
||||||
pthread_cond_init(&enc_request, NULL);
|
pthread_cond_init(&enc_request, NULL);
|
||||||
pthread_t vorbis_enc;
|
pthread_t vorbis_enc;
|
||||||
ved.m_data = &pcm_data;
|
ved.m_data = &audio_data;
|
||||||
ved.m_enc_request = &enc_request;
|
ved.m_enc_request = &enc_request;
|
||||||
pthread_create(&vorbis_enc, NULL, &Recorder::vorbisEncoder, &ved);
|
pthread_create(&vorbis_enc, NULL, &Recorder::vorbisEncoder, &ved);
|
||||||
const unsigned frag_size = 1024 * ved.m_channels *
|
const unsigned frag_size = 1024 * ved.m_channels *
|
||||||
(g_wasapi_data.m_wav_format->wBitsPerSample / 8);
|
(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;
|
unsigned readed = 0;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (idle->getAtomic())
|
if (idle->getAtomic())
|
||||||
{
|
{
|
||||||
pcm_data.lock();
|
audio_data.lock();
|
||||||
pcm_data.getData().push_back(each_pcm_buf);
|
audio_data.getData().push_back(each_audio_buf);
|
||||||
pthread_cond_signal(&enc_request);
|
pthread_cond_signal(&enc_request);
|
||||||
pcm_data.unlock();
|
audio_data.unlock();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
REFERENCE_TIME sleep_time = duration / 10000 / 2;
|
REFERENCE_TIME sleep_time = duration / 10000 / 2;
|
||||||
@ -224,25 +227,25 @@ namespace Recorder
|
|||||||
unsigned copy_size = buf_full ? frag_size - readed : bytes;
|
unsigned copy_size = buf_full ? frag_size - readed : bytes;
|
||||||
if (!(flags & AUDCLNT_BUFFERFLAGS_SILENT))
|
if (!(flags & AUDCLNT_BUFFERFLAGS_SILENT))
|
||||||
{
|
{
|
||||||
memcpy(each_pcm_buf + readed, data, copy_size);
|
memcpy(each_audio_buf + readed, data, copy_size);
|
||||||
}
|
}
|
||||||
if (buf_full)
|
if (buf_full)
|
||||||
{
|
{
|
||||||
pcm_data.lock();
|
audio_data.lock();
|
||||||
pcm_data.getData().push_back(each_pcm_buf);
|
audio_data.getData().push_back(each_audio_buf);
|
||||||
pthread_cond_signal(&enc_request);
|
pthread_cond_signal(&enc_request);
|
||||||
pcm_data.unlock();
|
audio_data.unlock();
|
||||||
each_pcm_buf = new int8_t[frag_size]();
|
each_audio_buf = new int8_t[frag_size]();
|
||||||
readed = (unsigned)bytes - copy_size;
|
readed = bytes - copy_size;
|
||||||
if (!(flags & AUDCLNT_BUFFERFLAGS_SILENT))
|
if (!(flags & AUDCLNT_BUFFERFLAGS_SILENT))
|
||||||
{
|
{
|
||||||
memcpy(each_pcm_buf, (uint8_t*)data + copy_size,
|
memcpy(each_audio_buf, (uint8_t*)data + copy_size,
|
||||||
readed);
|
readed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
readed += (unsigned)bytes;
|
readed += bytes;
|
||||||
}
|
}
|
||||||
hr = g_wasapi_data.m_capture_client->ReleaseBuffer(frame_size);
|
hr = g_wasapi_data.m_capture_client->ReleaseBuffer(frame_size);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
@ -257,10 +260,10 @@ namespace Recorder
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pcm_data.lock();
|
audio_data.lock();
|
||||||
pcm_data.getData().push_back(NULL);
|
audio_data.getData().push_back(NULL);
|
||||||
pthread_cond_signal(&enc_request);
|
pthread_cond_signal(&enc_request);
|
||||||
pcm_data.unlock();
|
audio_data.unlock();
|
||||||
pthread_join(vorbis_enc, NULL);
|
pthread_join(vorbis_enc, NULL);
|
||||||
pthread_cond_destroy(&enc_request);
|
pthread_cond_destroy(&enc_request);
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "config/user_config.hpp"
|
#include "config/user_config.hpp"
|
||||||
#include "graphics/irr_driver.hpp"
|
#include "graphics/irr_driver.hpp"
|
||||||
#include "guiengine/message_queue.hpp"
|
#include "guiengine/message_queue.hpp"
|
||||||
|
#include "recorder/vorbis_encoder.hpp"
|
||||||
#include "recorder/webm_writer.hpp"
|
#include "recorder/webm_writer.hpp"
|
||||||
#include "utils/translation.hpp"
|
#include "utils/translation.hpp"
|
||||||
#include "utils/vs.hpp"
|
#include "utils/vs.hpp"
|
||||||
@ -34,7 +35,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <turbojpeg.h>
|
#include <turbojpeg.h>
|
||||||
#include <vorbis/vorbisenc.h>
|
|
||||||
#include <vpx/vpx_encoder.h>
|
#include <vpx/vpx_encoder.h>
|
||||||
#include <vpx/vp8cx.h>
|
#include <vpx/vp8cx.h>
|
||||||
|
|
||||||
@ -377,113 +377,6 @@ void* AVIWriter::videoRecord(void *obj)
|
|||||||
return NULL;
|
return NULL;
|
||||||
} // videoRecord
|
} // 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<std::list<int8_t*> >* pcm_data =
|
|
||||||
(Synchronised<std::list<int8_t*> >*)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
|
#ifndef WIN32
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
void serverInfoCallBack(pa_context* c, const pa_server_info* i, void* data)
|
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;
|
sam_spec.channels = 2;
|
||||||
|
|
||||||
pa_buffer_attr buf_attr;
|
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;
|
buf_attr.fragsize = frag_size;
|
||||||
const unsigned max_uint = -1;
|
const unsigned max_uint = -1;
|
||||||
buf_attr.maxlength = max_uint;
|
buf_attr.maxlength = max_uint;
|
||||||
@ -564,10 +457,13 @@ void* AVIWriter::audioRecord(void *obj)
|
|||||||
pthread_cond_init(&enc_request, NULL);
|
pthread_cond_init(&enc_request, NULL);
|
||||||
pthread_t vorbis_enc_thread;
|
pthread_t vorbis_enc_thread;
|
||||||
|
|
||||||
EncoderInfo ei;
|
Recorder::VorbisEncoderData ved;
|
||||||
ei.m_data = &pcm_data;
|
ved.m_sample_rate = sam_spec.rate;
|
||||||
ei.m_enc_request = &enc_request;
|
ved.m_channels = sam_spec.channels;
|
||||||
pthread_create(&vorbis_enc_thread, NULL, &vorbisEncoder, &ei);
|
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]();
|
int8_t* each_pcm_buf = new int8_t[frag_size]();
|
||||||
unsigned readed = 0;
|
unsigned readed = 0;
|
||||||
while (true)
|
while (true)
|
||||||
|
@ -246,8 +246,6 @@ public:
|
|||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
static void* audioRecord(void *obj);
|
static void* audioRecord(void *obj);
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
static void* vorbisEncoder(void *obj);
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
static void* vpxEncoder(void *obj);
|
static void* vpxEncoder(void *obj);
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
static void setRecordingTarget(const std::string& name)
|
static void setRecordingTarget(const std::string& name)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user