在实现以下代码时,我会lip不休。
我正在使用ffmpeg从OSS设备复制到ALSA回送设备:
ffmpeg -fflags +genpts -nostats -nostdin -f oss -i /dev/dsp -codec:a pcm_s16le -ar 48000 -ac 1 -f alsa hw:0,0 > /dev/null &
--- PCM Information ---
PCM handle name = 'hw:0,1'
PCM state = RUNNING
access type = RW_INTERLEAVED
format = 'S16_LE' (Signed 16 bit Little Endian)
subformat = 'STD' (Standard)
channels = 1
rate = 48000 bps
period time = 21333 us
period size = 1024 frames
buffer time = 21845333 us
buffer size = 1048576 frames
periods per buffer = 1024 frames
exact rate = 48000/1 bps
significant bits = 16
tick time = 0 us
is batch = 0
is block transfer = 0
is double = 0
is half duplex = 0
is joint duplex = 0
can overrange = 0
can mmap = 1
can pause = 1
can resume = 1
can sync start = 0
size_t ALSACapture::read(char* buffer, size_t bufferSize)
{
// How often is this actually called?
// My best guess is it is called for every frame (i.e. 25FPS)
// In one call I fetch period time = 21333 us of audio
// m_periodSize by default seems to be 1024
int num_samples = bufferSize / sizeof(short);
short localBuffer[num_samples];
int bytesRead = 0;
size_t size = 0;
int fmt_phys_width_bytes = 0;
if (m_pcm != 0)
{
// bits per sample
int fmt_phys_width_bits = snd_pcm_format_physical_width(m_fmt);
// Bytes per sample (2 bytes)
fmt_phys_width_bytes = fmt_phys_width_bits / 8;
// Reading m_periodSize = 1024 * 16 bits
snd_pcm_sframes_t ret = snd_pcm_readi (m_pcm, buffer, m_periodSize*fmt_phys_width_bytes);
LOG(DEBUG) << "ALSA buffer in_size:" << m_periodSize*fmt_phys_width_bytes << " read_size:" << ret;
if (ret > 0) {
size = ret;
// swap if capture in not in network order
if (!snd_pcm_format_big_endian(m_fmt)) {
LOG(DEBUG) << "Swapping buffer because bytes are not in network order";
for(unsigned int i = 0; i < size; i++){
char * ptr = &buffer[i * fmt_phys_width_bytes * m_params.m_channels];
for(unsigned int j = 0; j < m_params.m_channels; j++){
ptr += j * fmt_phys_width_bytes;
for (int k = 0; k < fmt_phys_width_bytes/2; k++) {
char byte = ptr[k];
ptr[k] = ptr[fmt_phys_width_bytes - 1 - k];
ptr[fmt_phys_width_bytes - 1 - k] = byte;
}
}
}
}
}
}
bytesRead = size * m_params.m_channels * fmt_phys_width_bytes;
if (useOpus) {
// Copy contents of buffer to localBuffer
memcpy(&localBuffer, buffer, bufferSize);
// Encode the frame
bytesRead = opus_encode(encoder, localBuffer, 960, (unsigned char *)buffer, bufferSize);
if (bytesRead < 0) {
LOG(ERROR) << "Error encoding Opus frame: " << opus_strerror(bytesRead);
return -1;
}
}
LOG(DEBUG) << "Audio bytesRead: " << bytesRead;
return bytesRead;
}
我的问题归结为我使用的frame_size。由于我的ALSA / PCM周期为1024帧,但是opus_encode说它只能接受某些大小:
这必须是编码器采样率的Opus帧大小。对于 例如,在48 kHz时,允许值为120、240、480、960、1920, 和2880。
1024似乎不适合Opus的所有这些采样率。什么是这里的好方法?
所以不确定在这里我是否做错了什么。该代码来自v4l2rtspserver,我正尝试将其向前移植
这似乎已经在这里实现了,但是我无法弄清楚为什么他们的代码行得通,而行不通。
https://github.com/Dafang-Hacks/v4l2rtspserver-master/blob/master/src/ALSACapture.cpp#L516
这是我使用的默认基本代码,但将其破解以仅发送操作字节: https://github.com/mpromonet/v4l2rtspserver/blob/master/src/ALSACapture.cpp#L125
有关我所做更改的更多详细信息: https://github.com/tachang/v4l2rtspserver/pull/1/files