使用ffmpg 实现rtmp 推音频流的C++代码
时间: 2024-05-06 16:18:37 浏览: 174
以下是使用FFmpeg实现RTMP推送音频流的C++代码示例:
```c++
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/opt.h>
#include <libavutil/error.h>
#include <libavutil/mathematics.h>
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096
int main(int argc, char **argv)
{
AVOutputFormat *ofmt = NULL;
AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
AVPacket pkt;
AVCodecContext *dec_ctx = NULL, *enc_ctx = NULL;
AVCodec *encoder = NULL;
int stream_index = 0;
int ret = 0;
int64_t cur_pts = 0;
uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
uint8_t *data = NULL;
int data_size = 0;
const char *out_filename = "rtmp://localhost:1935/live/stream";
const char *in_filename = "test.mp3";
av_register_all();
// Open input file context
if ((ret = avformat_open_input(&ifmt_ctx, in_filename, NULL, NULL)) < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
goto end;
}
// Retrieve stream information
if ((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
goto end;
}
// Dump input information
av_dump_format(ifmt_ctx, 0, in_filename, 0);
// Open output file context
if ((ret = avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", out_filename)) < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot create output context\n");
goto end;
}
ofmt = ofmt_ctx->oformat;
// Add audio stream to output context
for (int i = 0; i < ifmt_ctx->nb_streams; i++) {
if (ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
AVStream *in_stream = ifmt_ctx->streams[i];
dec_ctx = avcodec_alloc_context3(NULL);
if (!dec_ctx) {
av_log(NULL, AV_LOG_ERROR, "Failed to allocate decoder context\n");
goto end;
}
ret = avcodec_parameters_to_context(dec_ctx, in_stream->codecpar);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Failed to copy decoder parameters to input decoder context\n");
goto end;
}
encoder = avcodec_find_encoder(AV_CODEC_ID_AAC);
if (!encoder) {
av_log(NULL, AV_LOG_ERROR, "Codec not found\n");
goto end;
}
enc_ctx = avcodec_alloc_context3(encoder);
if (!enc_ctx) {
av_log(NULL, AV_LOG_ERROR, "Failed to allocate encoder context\n");
goto end;
}
enc_ctx->channels = dec_ctx->channels;
enc_ctx->channel_layout = dec_ctx->channel_layout;
enc_ctx->sample_rate = dec_ctx->sample_rate;
enc_ctx->sample_fmt = encoder->sample_fmts[0];
enc_ctx->bit_rate = 128000;
if (ofmt->flags & AVFMT_GLOBALHEADER) {
enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
ret = avcodec_open2(enc_ctx, encoder, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Failed to open encoder\n");
goto end;
}
AVStream *out_stream = avformat_new_stream(ofmt_ctx, encoder);
if (!out_stream) {
av_log(NULL, AV_LOG_ERROR, "Failed to allocate output stream\n");
goto end;
}
ret = avcodec_parameters_copy(out_stream->codecpar, enc_ctx->codecpar);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Failed to copy encoder parameters to output stream\n");
goto end;
}
out_stream->codecpar->codec_tag = 0;
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
out_stream->codecpar->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
stream_index = out_stream->index;
break;
}
}
// Dump output information
av_dump_format(ofmt_ctx, 0, out_filename, 1);
// Open output file
if (!(ofmt->flags & AVFMT_NOFILE)) {
ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot open output file\n");
goto end;
}
}
// Write header to output file
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error occurred when opening output file\n");
goto end;
}
// Read frames from input file and write to output file
while (1) {
AVStream *in_stream, *out_stream;
// Read packet from input file
ret = av_read_frame(ifmt_ctx, &pkt);
if (ret < 0) {
break;
}
// Ignore packets that do not belong to the audio stream
if (pkt.stream_index != stream_index) {
av_packet_unref(&pkt);
continue;
}
in_stream = ifmt_ctx->streams[pkt.stream_index];
out_stream = ofmt_ctx->streams[pkt.stream_index];
// Calculate packet duration
AVRational time_base = in_stream->time_base;
int64_t pts_time = av_rescale_q(pkt.pts, time_base, AV_TIME_BASE_Q);
int64_t now_time = av_gettime() - cur_pts;
if (now_time < pts_time) {
av_usleep(pts_time - now_time);
}
// Decode audio frame
ret = avcodec_send_packet(dec_ctx, &pkt);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error sending packet to decoder\n");
goto end;
}
while (ret >= 0) {
AVFrame *decoded_frame = av_frame_alloc();
if (!decoded_frame) {
av_log(NULL, AV_LOG_ERROR, "Failed to allocate memory for decoded frame\n");
goto end;
}
ret = avcodec_receive_frame(dec_ctx, decoded_frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
av_frame_free(&decoded_frame);
break;
} else if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error receiving frame from decoder\n");
goto end;
}
// Encode audio frame
AVPacket enc_pkt;
av_init_packet(&enc_pkt);
enc_pkt.data = NULL;
enc_pkt.size = 0;
ret = avcodec_send_frame(enc_ctx, decoded_frame);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error sending frame to encoder\n");
goto end;
}
while (ret >= 0) {
ret = avcodec_receive_packet(enc_ctx, &enc_pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error receiving packet from encoder\n");
goto end;
}
// Write packet to output file
av_packet_rescale_ts(&enc_pkt, enc_ctx->time_base, out_stream->time_base);
enc_pkt.stream_index = stream_index;
ret = av_write_frame(ofmt_ctx, &enc_pkt);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error writing audio frame\n");
goto end;
}
av_packet_unref(&enc_pkt);
}
av_frame_free(&decoded_frame);
}
av_packet_unref(&pkt);
}
// Flush encoders
ret = avcodec_send_frame(enc_ctx, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error sending null frame to encoder\n");
goto end;
}
while (ret >= 0) {
AVPacket enc_pkt;
av_init_packet(&enc_pkt);
enc_pkt.data = NULL;
enc_pkt.size = 0;
ret = avcodec_receive_packet(enc_ctx, &enc_pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error receiving packet from encoder\n");
goto end;
}
av_packet_rescale_ts(&enc_pkt, enc_ctx->time_base, ofmt_ctx->streams[stream_index]->time_base);
enc_pkt.stream_index = stream_index;
ret = av_write_frame(ofmt_ctx, &enc_pkt);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error writing audio frame\n");
goto end;
}
av_packet_unref(&enc_pkt);
}
// Write trailer to output file
av_write_trailer(ofmt_ctx);
end:
avcodec_free_context(&dec_ctx);
avcodec_free_context(&enc_ctx);
avformat_close_input(&ifmt_ctx);
if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE)) {
avio_closep(&ofmt_ctx->pb);
}
avformat_free_context(ofmt_ctx);
if (ret < 0) {
char errbuf[AV_ERROR_MAX_STRING_SIZE] = {0};
av_strerror(ret, errbuf, sizeof(errbuf));
av_log(NULL, AV_LOG_ERROR, "Error occurred: %s\n", errbuf);
return 1;
}
return 0;
}
```
这段代码假设输入文件为MP3格式,输出文件为FLV格式,并且只包含一个音频流。代码将音频流从输入文件中解码,并使用AAC编码器编码成AAC格式,然后将编码后的音频流写入输出文件。在实际使用时,你需要根据你的需求进行相应的修改。
阅读全文