【问题标题】:Audio Metering with LibVLC使用 LibVLC 进行音频计量
【发布时间】:2016-07-01 09:48:58
【问题描述】:

我在 Windows C++ 应用程序中使用 LibVLC 来显示视频流。

我想监控传入的音频样本,以生成传递给我的应用程序另一部分的计量数据。我有这种与libvlc_audio_set_callbacks 合作的工作,除了a:我正在监视输出音频,所以它受静音等影响,b:当我启用它时,听不到音频(诚然,这是文档中描述的行为)。

有没有办法使用 LibVLC API 来实际执行此操作,或者我是否需要编写音频过滤器插件?

或者,我可以使用一些现有的通用“音频嗅探”插件吗?

【问题讨论】:

  • 如果您可以使用仅限 Windows 的解决方案,您可能需要查看Audio Mixers
  • @IInspectable 谢谢,但我需要能够处理来自网络流的音频。 :(
  • 您可能想看看提供的模块。包含很多核心模块。也就是说,实现一个模块并不太难。有关示例,请参见 audio bar graph 模块。 (float mixer 也是个不错的地方。)
  • @theB 我查看了有趣的音频条形图过滤器。但我无法弄清楚基于 libVLC 的代码如何调用(例如)`var_AddCallback(vlcInstance, "audiobargraph_v-i_values",...)`。我应该传递什么作为第一个参数?
  • 查看wiki.videolan.org/LibVLC_Tutorial,它显示了创建实例。

标签: c++ winapi audio libvlc


【解决方案1】:

回复有点晚了,但这是一个我难以解决的问题,其他人可能在同一个地方(即使 OP 早就继续前进了!)。

关键是使用smem插件。这使您可以在播放音频和视频时对其进行跟踪(有一些严重的警告,请参见下文)。为了同时播放和计量,您需要duplicate 流(拆分它)。以下是用于执行此操作的输出字符串:

std::ostringstream outstream;
outstream << ":sout=#duplicate{dst=std{access=file,dst=\"" << filepath << "\"},dst=\"transcode{acodec=s16l}:" << createFrameCallbackString(true) << "\"}";
libvlc_media_add_option(media, outstream.str().c_str());

我们需要创建一个输出链,在其中拆分流,从而调用duplicate。在副本中,有两个目的地。

outstream << ":sout=#duplicate{dst=...,dst=...}";

在我的示例中,我正在录制到文件(而不是显示到视频窗口),因此您希望将第一个目标替换为您自己的。 第二个目的地是我们使用smem 将音频(和/或视频)发送到回调方法的地方:

"..., dst=\"transcode{acodec=s16l}:" << createFrameCallbackString(true) << "\"}"

注意 smem 中的音频,它必须在 PCM 中(或者文档中似乎如此),因此我们将其转码为带符号的 16 位小端 (s16l)(最后是 L,而不是 1 )。 转码的间接费用是多少?在我的测试中,它似乎很小,但如果您有性能问题,值得一看。

为smem配置输出链如下:

class Player
{
//callback for frame monitoring
static void prerendercb(void *data, unsigned char** buffer, size_t size)
{
    //we must allocate a buffer in order for postrender to be called
    *buffer = (uint8_t *)malloc(size);
}

static void postrendercb(void *data, unsigned char* buffer, int width, int height, int pitch, size_t size, int64_t pts)
{
    Player* context = (Player*)data;
    //free the buffer
    free(buffer);
    //notify context of frame for processing
    context->OnFrame(/*pass it whatever information you need*/);
}
static void audio_prerendercb(void* data, unsigned char** buffer, size_t size)
{
    *buffer = (uint8_t *)malloc(size);
}
static void audio_postrendercb(void* data, unsigned char* buffer, unsigned int channels, unsigned int rate, 
        unsigned int nb_samples, unsigned int bits_per_sample, size_t size, int64_t pts)
{
    Player* context = (Player*)data;
    //free the buffer
    free(buffer);
    //notify context
    context->OnAudioFrame(/*whatever data is needed*/);
}

//Get an smem string for the audio/video callbacks
std::string Player::createFrameCallbackString(bool timesync) const
{
    std::ostringstream text;
    text <<
        "smem{" << "video-prerender-callback=" << ((long long int)(intptr_t)(void*)&prerendercb) << "," <<
                       "video-postrender-callback=" << ((long long int)(intptr_t)(void*)&postrendercb) << "," <<
                       "video-data=" << ((long long int)(intptr_t)(void*)this) << "," <<
                       "audio-prerender-callback=" << ((long long int)(intptr_t)(void*)&audio_prerendercb) << "," <<
                       "audio-postrender-callback=" << ((long long int)(intptr_t)(void*)&audio_postrendercb) << "," <<
                       "audio-data=" << ((long long int)(intptr_t)(void*)this) << "," <<
                       "time-sync=" << (timesync ? "1" : "0") <<
                       "}";

    return text.str();
}

}

注意事项
除了转码问题以及不管你是否关心都必须分配缓冲区数据这一事实之外,最大的问题是 libVLC异步处理帧。结果,您将倾向于获得一次处理 10、15 帧的突发,然后您将有一段时间看不到任何内容,然后是另一个突发。这肯定会受到缓存大小的影响(libVLC 中有几个),但即使将缓存大小设置得尽可能低,您仍然会得到至少 2 或 3 帧的突发。 设置这些选项很有帮助:

libvlc_media_add_option(media, ":clock-synchro=0"); //this setting is critical for realtime processing of audio stream!
libvlc_media_add_option(media, ":clock-jitter=0");

构建输出链时的另一个警告是注意引号和括号。可能在某处发布了指导方针,但对我来说这是一个反复试验。

最后,在smem 中使用time-sync 选项时,我从未注意到合理的区别。我确信它的设置很重要,但我无法确定如何设置。

我在使用 libVLC 时发现它并不是真正为这种用途而设计的。它可以被扭曲成可用的形状,但它的性能永远不会达到应有的水平。虽然它是开源的,但喜欢冒险的人也许可以通过修改源代码来制定更有效的解决方案。

【讨论】:

  • 哇。没想到这么长时间后会有这么好的答案。会试一试....
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-18
  • 2016-02-05
  • 2020-06-02
相关资源
最近更新 更多