Android 音视频深入 十七 FFmpeg 获取RTMP流保存为flv (附源码下载)

弱龄寄事外,委怀在琴书。这篇文章主要讲述Android 音视频深入 十七 FFmpeg 获取RTMP流保存为flv (附源码下载)相关的知识,希望能为你提供帮助。
项目地址
https://github.com/979451341/RtmpSave
这个项目主要代码我是从雷神那弄过来的,不愧是雷神,我就配个环境搞个界面就可以用代码了。
这一次说的是将RTMP流媒体保存成为一个本地的FLV文件。因为播放视频本身占有很多技术难点,我先不做边获取RTMP流边播放了,这一次主要说如何获取RTMP流。
说说代码
初始化组件和网络环境

av_register_all(); //Network avformat_network_init();

打开RTMP流,获取RTMP流的信息,并搜索到其中视频流的位置
//Input if ((ret = avformat_open_input(& ifmt_ctx, in_filename, 0, 0)) < 0) { printf( "Could not open input file."); goto end; } if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) { printf( "Failed to retrieve input stream information"); goto end; }for(i=0; i< ifmt_ctx-> nb_streams; i++) if(ifmt_ctx-> streams[i]-> codec-> codec_type==AVMEDIA_TYPE_VIDEO){ videoindex=i; break; }

将RTMP流的一些配置信息保存在输入环境信息
av_dump_format(ifmt_ctx, 0, in_filename, 0);

根据输出flv文件名称和路径得到输出环境信息
avformat_alloc_output_context2(& ofmt_ctx, NULL, NULL, out_filename); //RTMPif (!ofmt_ctx) { printf( "Could not create output context\n"); ret = AVERROR_UNKNOWN; goto end; }

把输出环境信息的输出格式信息保存在ofmt
ofmt = ofmt_ctx-> oformat;
创建一条输出环境信息的流,就将输如环境信息里一条流复制到其中,并对每一条流的编码做出配置
for (i = 0; i < ifmt_ctx-> nb_streams; i++) { //Create output AVStream according to input AVStream AVStream *in_stream = ifmt_ctx-> streams[i]; AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream-> codec-> codec); if (!out_stream) { printf( "Failed allocating output stream\n"); ret = AVERROR_UNKNOWN; goto end; } //Copy the settings of AVCodecContext ret = avcodec_copy_context(out_stream-> codec, in_stream-> codec); if (ret < 0) { printf( "Failed to copy context from input to output stream codec context\n"); goto end; } out_stream-> codec-> codec_tag = 0; if (ofmt_ctx-> oformat-> flags & AVFMT_GLOBALHEADER) out_stream-> codec-> flags |= CODEC_FLAG_GLOBAL_HEADER; }

调试函数
av_dump_format(ofmt_ctx, 0, out_filename, 1);
打开输出url路径
if (!(ofmt-> flags & AVFMT_NOFILE)) { ret = avio_open(& ofmt_ctx-> pb, out_filename, AVIO_FLAG_WRITE); if (ret < 0) { printf( "Could not open output URL ‘%s‘", out_filename); goto end; } }

向输出环境写入文件头部
//Write file header ret = avformat_write_header(ofmt_ctx, NULL); if (ret < 0) { printf( "Error occurred when opening output URL\n"); goto end; }

配置H264编码器
#if USE_H264BSF
AVBitStreamFilterContext* h264bsfc =av_bitstream_filter_init(" h264_mp4toannexb" );
#endif
开始循环读帧写入flv文件
读取一帧RTMP流的视屏流数据
ret = av_read_frame(ifmt_ctx, & pkt); if (ret < 0) break;

计算对应这一帧输入RTMP流数据的一帧输出数据的相关显示帧时间pts,解码帧时间dts,距离上一帧到下一帧的播放时间差距duration
pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream-> time_base, out_stream-> time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX)); pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream-> time_base, out_stream-> time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX)); pkt.duration = av_rescale_q(pkt.duration, in_stream-> time_base, out_stream-> time_base);

根据H264编码格式转换一帧输出数据
#if USE_H264BSF
av_bitstream_filter_filter(h264bsfc, in_stream-> codec, NULL, & pkt.data, & pkt.size, pkt.data, pkt.size, 0);
#endif
将这一帧输出数据写入flv文件,然后释放这一帧数据
ret = av_interleaved_write_frame(ofmt_ctx, & pkt); if (ret < 0) { printf( "Error muxing packet\n"); break; }av_free_packet(& pkt);

关闭H264编码器
#if USE_H264BSF
av_bitstream_filter_close(h264bsfc);
#endif
释放输入、输出环境
av_write_trailer(ofmt_ctx); end: avformat_close_input(& ifmt_ctx); /* close output */ if (ofmt_ctx & & !(ofmt-> flags & AVFMT_NOFILE)) avio_close(ofmt_ctx-> pb); avformat_free_context(ofmt_ctx); if (ret < 0 & & ret != AVERROR_EOF) { printf( "Error occurred.\n"); return -1; }

说说app的使用
【Android 音视频深入 十七 FFmpeg 获取RTMP流保存为flv (附源码下载)】那个点击button就可以了,点击后它会字样会变成started,这样他就在保存RTMP流文件了,过一两分钟就相应路径去看就可以了

    推荐阅读