O código é implementado da seguinte forma:
#include <thread>
#include <iostream>
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
}
int main()
{
AVOutputFormat *ofmt = NULL;
AVFormatContext *ifmt_ctx = NULL;
AVFormatContext *ofmt_ctx = NULL;
AVPacket *pkt = NULL;
const char *in_filename = "rtmp://vlive2018.people.com.cn/2010/cctv132019/live_2000";
const char *out_filename = "out.flv";
int ret = -1;
bool stop = false;
// 初始化网络
avformat_network_init();
// 初始化输入格式上下文
if ((ifmt_ctx = avformat_alloc_context()) == NULL) {
std:: cout << "avformat_alloc_context failed." << std::endl;
exit(1);
}
// 打开输入格式上下文
if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
std:: cout << "Could not open input file." << std::endl;
exit(1);
}
// 获取输入信息
if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
std:: cout << "Failed to retrieve input stream information" << std::endl;
return -1;
}
// 申请pkt
if (!(pkt = av_packet_alloc())) {
std:: cout << "Could not allocate packet"<< std::endl;
return -1;
}
// 打开输出格式上下文
if ((ret = avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename)) < 0 || !ofmt_ctx) {
std:: cout << "Could not create output context" << std::endl;
return -1;
}
ofmt = ofmt_ctx->oformat;
// 关联输入输出
for (int i = 0; i < ifmt_ctx->nb_streams; i++) {
AVStream *in_stream = ifmt_ctx->streams[i];
AVStream *out_stream = avformat_new_stream(ofmt_ctx, NULL);
if (!out_stream) {
std:: cout << "Failed allocating output stream" << std::endl;
} else
{
if ((ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar)) < 0) {
std:: cout << "Failed to copy codec context to out_stream codecpar context" << std::endl;
}
}
}
av_dump_format(ifmt_ctx, 0, in_filename, 0);
av_dump_format(ofmt_ctx, 0, out_filename, 1);
if (!(ofmt->flags & AVFMT_NOFILE)) {
if ((ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE)) < 0) {
std:: cout << "Could not open output URL" << std::string(out_filename) << std::endl;
return -1;
}
}
// 写入头
if ((ret = avformat_write_header(ofmt_ctx, NULL)) < 0) {
std:: cout << "Error occurred when opening output URL" << std::endl;
return -1;
}
std::thread th([&]{
while (av_read_frame(ifmt_ctx, pkt) >= 0 && !stop) {
// 写入数据
if (av_interleaved_write_frame(ofmt_ctx, pkt) < 0) {
std:: cout << "Error muxing packet" << std::endl;
break;
}
av_packet_unref(pkt);
}
// 写入尾数据
av_write_trailer(ofmt_ctx);
});
std::cout << "input char to stop" << std::endl;
while(getchar() != 'q');
stop = true;
if (th.joinable())
{
th.join();
}
// 释放
avformat_close_input(&ifmt_ctx);
av_packet_free(&pkt);
/* close output */
if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE)) {
avio_close(ofmt_ctx->pb);
}
avformat_free_context(ofmt_ctx);
return 0;
}