Encoding FFmpeg API-转码和发送脉冲音频输入(rtsp)
我的目标是读取pulseaudio麦克风音频输入,并通过编码为opus的rtsp发送。要播放流,我使用ffplay 我错过了哪一步?目前我在接收流时只听到噪音。有趣的是,Encoding FFmpeg API-转码和发送脉冲音频输入(rtsp),encoding,ffmpeg,transcoding,Encoding,Ffmpeg,Transcoding,我的目标是读取pulseaudio麦克风音频输入,并通过编码为opus的rtsp发送。要播放流,我使用ffplay 我错过了哪一步?目前我在接收流时只听到噪音。有趣的是,av_dump_格式显示正确的输出: Input #0, pulse, from 'default': Duration: N/A, start: 1602879120.276839, bitrate: 1536 kb/s Stream #0:0: Audio: pcm_s16le, 48000 Hz, 2 chan
av_dump_格式
显示正确的输出:
Input #0, pulse, from 'default':
Duration: N/A, start: 1602879120.276839, bitrate: 1536 kb/s
Stream #0:0: Audio: pcm_s16le, 48000 Hz, 2 channels, s16, 1536 kb/s
Output #0, rtsp, to 'rtsp://localhost:8191/call':
Stream #0:0: Audio: opus, 8000 Hz, mono, s16, 16 kb/s
但ffplay显示不同的流参数:
Input #0, rtsp, from 'rtsp://localhost:8191/call':sq= 0B f=0/0
Metadata:
title : No Name
Duration: N/A, start: 51444.871521, bitrate: N/A
Stream #0:0: Audio: opus, 48000 Hz, stereo, fltp
#包括
#包括
#包括
#包括
int main(int argc,char*argv[])
{
int-ret,got_帧,got_包;
常量字符*音频输入;
常量字符*输出;
AVOutputFormat*out\U format=NULL;
AVInputFormat*in_format=NULL;
AVFormatContext*格式为\u ctx=NULL;
AVFormatContext*out\u format\u ctx=NULL;
AVCodec*in_codec=NULL;
AVCODECTCONTEXT*in_codec_ctx=NULL;
AVCodec*out_codec=NULL;
AVCodecContext*out\u codec\u ctx=NULL;
AVPacket packet={.data=NULL,.size=0};
AVFrame*frame=NULL;
AVDictionary*opt=NULL;
AVStream*ost;
av_寄存器_all();
avdevice_register_all();
音频输入=argv[1];
输出=argv[2];
//输入
//以选定格式打开输入
in_format=av_find_input_format(“脉冲”);
if((ret=avformat\u open\u输入(&in\u format\u ctx,audio\u输入,in\u format,NULL))!=0)
{
fprintf(stderr,“无法打开音频输入:%s.%s\n”,音频输入,av_err2str(ret));
出口(1);
}
//在标题中查找流信息并显示
if((ret=avformat\u find\u stream\u info(in\u format\u ctx,NULL))流[0]->codec->codec\u id);
if(in_codec==NULL){
fprintf(stderr,“不支持的解码器。\n”);
出口(1);
}
//为麦克风输入编解码器上下文分配内存(所有信息)
in_codec_ctx=avcodec_alloc_context3(in_codec);
if((ret=avcodec\u copy\u上下文(在\u codec\u ctx中,在\u格式\u ctx->streams[0]->codec))!=0){
fprintf(stderr,“无法复制编解码器上下文。%s\n”,av_err2str(ret));
出口(1);
}
//使用选定的编解码器和编解码器上下文
格式的if((ret=avcodec_open2(in_codec_ctx,in_codec,NULL));
/*如果需要,请打开输出文件*/
out\u codec=avcodec\u find\u编码器(AV\u codec\u ID\u OPUS);
if(out_codec==NULL){
fprintf(stderr,“不支持的编码器。\n”);
出口(1);
}
out\u codec\u ctx=avcodec\u alloc\u context3(out\u codec);
如果(!out\u codec\u ctx){
fprintf(stderr,“无法分配编码上下文\n”);
出口(1);
}
/*检查编码器是否支持s16 pcm输入*/
out_codec_ctx->sample_fmt=AV_sample_fmt_S16;
out_codec_ctx->比特率=16000;
out_codec_ctx->采样率=8000;
out_codec_ctx->channels=1;
out_codec_ctx->channel_layout=AV_Chu layout_MONO;
out\u codec\u ctx->channels=av\u get\u channel\u layout\u nb\u channels(out\u codec\u ctx->channel\u layout);
if(输出格式ctx->oformat->标志和AVFMT\U全局标题)
out_codec_ctx->flags |=AV_codec_FLAG_GLOBAL_头;
ret=avcodec_open2(out_codec_ctx,out_codec,NULL);
如果(ret<0){
fprintf(stderr,“无法打开音频编解码器:%s\n”,av_err2str(ret));
出口(1);
}
ost=avformat\ U new\ U stream(out\ U format\ U ctx,NULL);
如果(!ost){
fprintf(stderr,“无法分配流”\n);
出口(1);
}
ost->id=0;
ret=来自上下文的avcodec参数(ost->codecpar,out codec\U ctx);
如果(ret<0){
av_日志(NULL,av_日志错误,“无法将编码器参数复制到输出流。%s\n”,av_err2str(ret));
返回ret;
}
ost->time\u base=out\u codec\u ctx->time\u base;
av_转储_格式(out_格式_ctx,0,输出,1);
/*将流参数复制到muxer*/
ret=来自上下文的avcodec参数(ost->codecpar,out codec\U ctx);
如果(ret<0){
fprintf(stderr,“无法复制流参数。%s\n”,av_err2str(ret));
出口(1);
}
如果(!(输出格式ctx->oformat->flags&AVFMT\U NOFILE)){
ret=avio_打开(&out_格式\u ctx->pb,输出,avio_标志\u写入);
如果(ret<0){
av_日志(NULL,av_日志错误,“无法打开输出文件“%s”,输出);
返回ret;
}
}
/*初始化muxer,写入输出文件头*/
ret=avformat\U write\U头(out\U format\U ctx,NULL);
如果(ret<0){
av_日志(NULL,av_日志_错误,“打开输出文件时出错\n”);
返回ret;
}
而(1)
{
如果((ret=av_读取_帧(格式为ctx和数据包))<0)
{
fprintf(stderr,“读取帧失败。%s\n”,av_err2str(ret));
打破
}
frame=av_frame_alloc();
如果(!帧){
ret=平均值(ENOMEM);
打破
}
av_数据包\u重新缩放\u ts(数据包,格式为\u ctx->streams[0]->时基,编码解码器\u ctx->时基);
如果((ret=avcodec\U decode\U audio4(in\U codec\U ctx、帧和got\U帧和数据包))<0)
{
av_无帧(&帧);
fprintf(stderr,“音频解码失败。%s\n”,av_err2str(ret));
打破
}
frame->nb\u samples=out\u codec\u ctx->frame\u size;
如果((ret=av_帧_获取_缓冲区(帧,0))
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
int ret,got_frame,got_packet;
const char *audio_input;
const char *output;
AVOutputFormat *out_format = NULL;
AVInputFormat *in_format = NULL;
AVFormatContext *in_format_ctx = NULL;
AVFormatContext *out_format_ctx = NULL;
AVCodec *in_codec = NULL;
AVCodecContext *in_codec_ctx = NULL;
AVCodec *out_codec = NULL;
AVCodecContext *out_codec_ctx = NULL;
AVPacket packet = { .data = NULL, .size = 0 };
AVFrame *frame = NULL;
AVDictionary *opt = NULL;
AVStream *ost;
av_register_all();
avdevice_register_all();
audio_input = argv[1];
output = argv[2];
//INPUT
//Open input in selected format
in_format = av_find_input_format("pulse");
if((ret = avformat_open_input(&in_format_ctx, audio_input, in_format, NULL))!=0)
{
fprintf(stderr,"Could not open audio input: %s. %s\n",audio_input,av_err2str(ret));
exit(1);
}
//Find stream info in header and display
if((ret = avformat_find_stream_info(in_format_ctx, NULL))<0)
{
fprintf(stderr,"Could not find stream information. %s\n",av_err2str(ret));
exit(1);
}
av_dump_format(in_format_ctx, 0, audio_input, 0);
in_codec = avcodec_find_decoder(in_format_ctx->streams[0]->codec->codec_id);
if(in_codec==NULL) {
fprintf(stderr, "Unsupported decoder.\n");
exit(1);
}
//Allocate memory for microphone input codec context (all information)
in_codec_ctx = avcodec_alloc_context3(in_codec);
if((ret = avcodec_copy_context(in_codec_ctx, in_format_ctx->streams[0]->codec)) != 0) {
fprintf(stderr, "Couldn't copy codec context. %s\n",av_err2str(ret));
exit(1);
}
//Use selected codec and codec context
if((ret = avcodec_open2(in_codec_ctx, in_codec, NULL))<0)
{
fprintf(stderr, "Could not open audio codec. %s\n",av_err2str(ret));
exit(1);
}
//OUTPUT
ret = avformat_alloc_output_context2(&out_format_ctx, NULL, "rtsp", output);
if (!out_format_ctx) {
fprintf(stderr, "Output format ptoblem. %s\n",av_err2str(ret));
exit(1);
}
out_format = out_format_ctx->oformat;
/* open the output file, if needed */
out_codec = avcodec_find_encoder(AV_CODEC_ID_OPUS);
if(out_codec==NULL) {
fprintf(stderr, "Unsupported encoder.\n");
exit(1);
}
out_codec_ctx = avcodec_alloc_context3(out_codec);
if (!out_codec_ctx) {
fprintf(stderr, "Could not alloc an encoding context\n");
exit(1);
}
/* check that the encoder supports s16 pcm input */
out_codec_ctx->sample_fmt = AV_SAMPLE_FMT_S16;
out_codec_ctx->bit_rate = 16000;
out_codec_ctx->sample_rate = 8000;
out_codec_ctx->channels = 1;
out_codec_ctx->channel_layout = AV_CH_LAYOUT_MONO;
out_codec_ctx->channels = av_get_channel_layout_nb_channels(out_codec_ctx->channel_layout);
if (out_format_ctx->oformat->flags & AVFMT_GLOBALHEADER)
out_codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
ret = avcodec_open2(out_codec_ctx, out_codec, NULL);
if (ret < 0) {
fprintf(stderr, "Could not open audio codec: %s\n", av_err2str(ret));
exit(1);
}
ost = avformat_new_stream(out_format_ctx, NULL);
if (!ost) {
fprintf(stderr, "Could not allocate stream\n");
exit(1);
}
ost->id=0;
ret = avcodec_parameters_from_context(ost->codecpar, out_codec_ctx);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Failed to copy encoder parameters to output stream. %s\n",av_err2str(ret));
return ret;
}
ost->time_base = out_codec_ctx->time_base;
av_dump_format(out_format_ctx, 0, output, 1);
/* copy the stream parameters to the muxer */
ret = avcodec_parameters_from_context(ost->codecpar, out_codec_ctx);
if (ret < 0) {
fprintf(stderr, "Could not copy the stream parameters. %s\n",av_err2str(ret));
exit(1);
}
if (!(out_format_ctx->oformat->flags & AVFMT_NOFILE)) {
ret = avio_open(&out_format_ctx->pb, output, AVIO_FLAG_WRITE);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Could not open output file '%s'", output);
return ret;
}
}
/* init muxer, write output file header */
ret = avformat_write_header(out_format_ctx, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error occurred when opening output file\n");
return ret;
}
while(1)
{
if((ret = av_read_frame(in_format_ctx, &packet)) < 0)
{
fprintf(stderr, "Reading frame failed. %s\n",av_err2str(ret));
break;
}
frame = av_frame_alloc();
if (!frame) {
ret = AVERROR(ENOMEM);
break;
}
av_packet_rescale_ts(&packet,in_format_ctx->streams[0]->time_base,in_codec_ctx->time_base);
if((ret = avcodec_decode_audio4(in_codec_ctx,frame,&got_frame,&packet)) < 0)
{
av_frame_free(&frame);
fprintf(stderr, "Audio decoding failed. %s\n",av_err2str(ret));
break;
}
frame->nb_samples = out_codec_ctx->frame_size;
if((ret = av_frame_get_buffer(frame, 0))<0)
{
fprintf(stderr, "Error allocating an audio buffer. %s\n",av_err2str(ret));
break;
}
if(got_frame)
{
if((ret = avcodec_encode_audio2(out_codec_ctx,&packet,frame,&got_packet)) < 0)
{
av_frame_free(&frame);
fprintf(stderr, "Audio encoding failed. %d %s\n",ret,av_err2str(ret));
break;
}
}
av_frame_free(&frame);
if(got_packet)
{
if((ret = av_interleaved_write_frame(out_format_ctx,&packet)) < 0)
{
av_packet_unref(&packet);
fprintf(stderr, "Writing frame error. %s\n",av_err2str(ret));
break;
}
}
av_packet_unref(&packet);
}
}