avcodec_open2: PCM频道越界
avcodec_open2: PCM channels out of bounds
我试图在我的应用程序中读取音频 RTP 流,但出现此错误:
[pcm_mulaw @ 03390580] PCM channels out of bounds
我可以使用 ffplay 读取 RTP 流:
ffplay -i test.sdp -protocol_whitelist file,udp,rtp
我使用此命令生成 RTP 流:
ffmpeg -re -f lavfi -i aevalsrc="sin(400*2*PI*t)" -ar 8000 -f mulaw -f rtp rtp://127.0.0.1:8554
// SDP
v=0
o=- 0 0 IN IP4 127.0.0.1
s=No Name
c=IN IP4 127.0.0.1
t=0 0
a=tool:libavformat 57.25.101
m=audio 8554 RTP/AVP 0
b=AS:64
这是我的源代码:
#include "stdafx.h"
#include <math.h>
extern "C"
{
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libavutil/samplefmt.h>
#include <libavformat/avformat.h>
}
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096
#define ERRBUFFLEN 200
char errbuf[ERRBUFFLEN];
#define av_err2str(ret) av_strerror(ret, errbuf, ERRBUFFLEN)
/*
* Audio decoding.
*/
static void audio_decode_example(const char *outfilename, const char *filename)
{
AVCodec *inCodec;
AVCodecContext *inCodecCtx = NULL;
int len;
FILE *f, *outfile;
uint8_t inbuf[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
AVPacket avpkt;
AVFrame *decoded_frame = NULL;
AVFormatContext *inFormatCtx = NULL;
AVFrame *inFrame = NULL;
AVFrame *outFrame = NULL;
int ret;
av_init_packet(&avpkt);
AVDictionary *d = NULL; // "create" an empty dictionary
int listen = false;
listen = true;
if (listen)
{
av_dict_set(&d, "protocol_whitelist", "file,udp,rtp", 0); // add an entry
printf("Listening mode.\n");
}
else {
printf("Connecting mode.\n");
}
// Open video file
ret = avformat_open_input(&inFormatCtx, filename, NULL, &d);
if (ret <0)
{
printf_s("Failed: cannot open input.\n");
av_strerror(ret, errbuf, ERRBUFFLEN);
fprintf(stderr, "avformat_open_input() fail: %s\n", errbuf);
exit(1);
}
printf_s("Retrieve stream information.\n");
ret = avformat_find_stream_info(inFormatCtx, NULL);
if (ret <0)
{
printf_s("Failed: cannot find stream.\n");
av_strerror(ret, errbuf, ERRBUFFLEN);
fprintf(stderr, "avformat_find_stream_info() fail: %s\n", errbuf);
exit(1);
}
av_dump_format(inFormatCtx, 0, filename, 0);
int stream_idx = -1;
for (int i = 0; i < inFormatCtx->nb_streams; i++)
if (inFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
stream_idx = i;
break;
}
if (stream_idx == -1)
{
fprintf(stderr, "Video stream not found\n");
exit(1);
}
inCodec = avcodec_find_decoder(inFormatCtx->streams[stream_idx]->codec->codec_id);
if (!inCodec) {
fprintf(stderr, "Codec not found\n");
exit(1);
}
inCodecCtx = avcodec_alloc_context3(inCodec);
if (!inCodecCtx) {
fprintf(stderr, "Could not allocate audio codec context\n");
exit(1);
}
/* Error here */
ret = avcodec_open2(inCodecCtx, inCodec, NULL);
if (ret < 0) {
fprintf(stderr, "Could not open codec: %s\n", av_err2str(ret));
exit(1);
}
(...more code)
我知道出了点问题,但那是什么?非常感谢您的建议和提示。
我发现流属性没有自动设置,所以我必须在调用之前手动设置它们 avcodec_open2()
:
inCodecCtx->sample_rate = 8000;
inCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;
inCodecCtx->channels = 1;
inCodecCtx->channel_layout = AV_CH_LAYOUT_MONO;
希望这对遇到与我相同问题的人有所帮助。
谢谢,你帮了我:-D
只是想补充一下,如果你不知道它们,你可以从文件中获取这些参数。
这是我的代码,用于搜索音频流、为其获取解码器并设置 formatContext 中的参数。
请注意,我的代码是 Scala 调用 Java-CPP 包装器围绕 FFMEG
val formatContext = chkNull(avformat.avformat_alloc_context())
val inputFormat = avformat.av_find_input_format(format)
if (inputFormat == null) throw new Error(s"Format '${format}' is not supported")
formatContext.iformat(inputFormat)
chk(avformat.avformat_open_input(formatContext, "<path to audio file goes here>", null, null))
val audioStreams = (0 until formatContext.nb_streams) filter { i: Int =>
formatContext.streams(i).codecpar().codec_type() == avutil.AVMEDIA_TYPE_AUDIO
}
val audioStream = audioStreams.size match {
case 0 => throw new Error("No Audio Stream found")
case 1 => audioStreams.head
case _ => throw new Error("More than one Audio Streams found")
}
val codecParameters = formatContext.streams(audioStream).codecpar()
val decoder = chkNull(avcodec.avcodec_find_decoder(codecParameters.codec_id()))
val codecContext = chkNull(avcodec.avcodec_alloc_context3(decoder))
codecContext.sample_rate(codecParameters.sample_rate())
codecContext.sample_fmt(codecParameters.format())
codecContext.channels(codecParameters.channels())
codecContext.channel_layout(codecParameters.channel_layout())
chk(avcodec.avcodec_open2(codecContext, null, null.asInstanceOf[AVDictionary]))
avcodec.h中还有一个专用函数:
int error = avcodec_parameters_to_context(inCodecCtx, inFormatCtx->streams[stream_idx]->codecpar);
if (error < 0) {
// something went wrong
}
(参见 https://www.ffmpeg.org/doxygen/3.2/demuxing__decoding_8c_source.html,第 182 行)。
我试图在我的应用程序中读取音频 RTP 流,但出现此错误:
[pcm_mulaw @ 03390580] PCM channels out of bounds
我可以使用 ffplay 读取 RTP 流:
ffplay -i test.sdp -protocol_whitelist file,udp,rtp
我使用此命令生成 RTP 流:
ffmpeg -re -f lavfi -i aevalsrc="sin(400*2*PI*t)" -ar 8000 -f mulaw -f rtp rtp://127.0.0.1:8554
// SDP
v=0
o=- 0 0 IN IP4 127.0.0.1
s=No Name
c=IN IP4 127.0.0.1
t=0 0
a=tool:libavformat 57.25.101
m=audio 8554 RTP/AVP 0
b=AS:64
这是我的源代码:
#include "stdafx.h"
#include <math.h>
extern "C"
{
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libavutil/samplefmt.h>
#include <libavformat/avformat.h>
}
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096
#define ERRBUFFLEN 200
char errbuf[ERRBUFFLEN];
#define av_err2str(ret) av_strerror(ret, errbuf, ERRBUFFLEN)
/*
* Audio decoding.
*/
static void audio_decode_example(const char *outfilename, const char *filename)
{
AVCodec *inCodec;
AVCodecContext *inCodecCtx = NULL;
int len;
FILE *f, *outfile;
uint8_t inbuf[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
AVPacket avpkt;
AVFrame *decoded_frame = NULL;
AVFormatContext *inFormatCtx = NULL;
AVFrame *inFrame = NULL;
AVFrame *outFrame = NULL;
int ret;
av_init_packet(&avpkt);
AVDictionary *d = NULL; // "create" an empty dictionary
int listen = false;
listen = true;
if (listen)
{
av_dict_set(&d, "protocol_whitelist", "file,udp,rtp", 0); // add an entry
printf("Listening mode.\n");
}
else {
printf("Connecting mode.\n");
}
// Open video file
ret = avformat_open_input(&inFormatCtx, filename, NULL, &d);
if (ret <0)
{
printf_s("Failed: cannot open input.\n");
av_strerror(ret, errbuf, ERRBUFFLEN);
fprintf(stderr, "avformat_open_input() fail: %s\n", errbuf);
exit(1);
}
printf_s("Retrieve stream information.\n");
ret = avformat_find_stream_info(inFormatCtx, NULL);
if (ret <0)
{
printf_s("Failed: cannot find stream.\n");
av_strerror(ret, errbuf, ERRBUFFLEN);
fprintf(stderr, "avformat_find_stream_info() fail: %s\n", errbuf);
exit(1);
}
av_dump_format(inFormatCtx, 0, filename, 0);
int stream_idx = -1;
for (int i = 0; i < inFormatCtx->nb_streams; i++)
if (inFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
stream_idx = i;
break;
}
if (stream_idx == -1)
{
fprintf(stderr, "Video stream not found\n");
exit(1);
}
inCodec = avcodec_find_decoder(inFormatCtx->streams[stream_idx]->codec->codec_id);
if (!inCodec) {
fprintf(stderr, "Codec not found\n");
exit(1);
}
inCodecCtx = avcodec_alloc_context3(inCodec);
if (!inCodecCtx) {
fprintf(stderr, "Could not allocate audio codec context\n");
exit(1);
}
/* Error here */
ret = avcodec_open2(inCodecCtx, inCodec, NULL);
if (ret < 0) {
fprintf(stderr, "Could not open codec: %s\n", av_err2str(ret));
exit(1);
}
(...more code)
我知道出了点问题,但那是什么?非常感谢您的建议和提示。
我发现流属性没有自动设置,所以我必须在调用之前手动设置它们 avcodec_open2()
:
inCodecCtx->sample_rate = 8000;
inCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;
inCodecCtx->channels = 1;
inCodecCtx->channel_layout = AV_CH_LAYOUT_MONO;
希望这对遇到与我相同问题的人有所帮助。
谢谢,你帮了我:-D
只是想补充一下,如果你不知道它们,你可以从文件中获取这些参数。
这是我的代码,用于搜索音频流、为其获取解码器并设置 formatContext 中的参数。
请注意,我的代码是 Scala 调用 Java-CPP 包装器围绕 FFMEG
val formatContext = chkNull(avformat.avformat_alloc_context())
val inputFormat = avformat.av_find_input_format(format)
if (inputFormat == null) throw new Error(s"Format '${format}' is not supported")
formatContext.iformat(inputFormat)
chk(avformat.avformat_open_input(formatContext, "<path to audio file goes here>", null, null))
val audioStreams = (0 until formatContext.nb_streams) filter { i: Int =>
formatContext.streams(i).codecpar().codec_type() == avutil.AVMEDIA_TYPE_AUDIO
}
val audioStream = audioStreams.size match {
case 0 => throw new Error("No Audio Stream found")
case 1 => audioStreams.head
case _ => throw new Error("More than one Audio Streams found")
}
val codecParameters = formatContext.streams(audioStream).codecpar()
val decoder = chkNull(avcodec.avcodec_find_decoder(codecParameters.codec_id()))
val codecContext = chkNull(avcodec.avcodec_alloc_context3(decoder))
codecContext.sample_rate(codecParameters.sample_rate())
codecContext.sample_fmt(codecParameters.format())
codecContext.channels(codecParameters.channels())
codecContext.channel_layout(codecParameters.channel_layout())
chk(avcodec.avcodec_open2(codecContext, null, null.asInstanceOf[AVDictionary]))
avcodec.h中还有一个专用函数:
int error = avcodec_parameters_to_context(inCodecCtx, inFormatCtx->streams[stream_idx]->codecpar);
if (error < 0) {
// something went wrong
}
(参见 https://www.ffmpeg.org/doxygen/3.2/demuxing__decoding_8c_source.html,第 182 行)。