难以获得正常播放的作品

时间:2020-10-17 19:25:34

标签: alsa opus

在实现以下代码时,我会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

0 个答案:

没有答案