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); //RTMP

if (!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的使用

那个点击button就可以了,点击后它会字样会变成started,这样他就在保存RTMP流文件了,过一两分钟就相应路径去看就可以了

原文地址:http://blog.51cto.com/13591594/2074204

时间: 2024-10-20 20:23:32

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

Android 音视频深入 十九 使用ijkplayer做个视频播放器(附源码下载)

项目地址https://github.com/979451341/Myijkplayer 前段时候我觉得FFmpeg做个视频播放器好难,虽然播放上没问题,但暂停还有通过拖动进度条来设置播放进度,这些都即便做得到,可以那个延缓..... 现在学习一下目前移动端最知名的视频播放器的框架ijkplayer,这个框架他是基于FFmpeg.SDL.还有安卓原生API MediaCodec之类的.他是没有播放界面的,这个需要我们去做,所以这个里我就做个基于ijkplayer的视频播放器,随便浅显的说一下ij

Android学习笔记(十六)——碎片之间进行交互(附源码)

碎片之间进行交互 点击下载源码 很多时候,一个活动中包含一个或者多个碎片,它们彼此协作,向用户展示一个一致的UI.在这种情况下,碎片之间能进行通信并交换数据十分重要. 1.使用上一篇中创建的同一个项目,在fragment.xml中添加TextView的标识id: android:id="@+id/lblFragment1" 2.在fragment2.xml中添加一个Button,用于与fragment1进行交互: <Button android:id="@+id/btn

Android学习笔记(十五)——碎片的生命周期(附源码)

碎片的生命周期 点击下载源码 与活动类似,碎片具有自己的生命周期.理解了碎片的生命周期后,我们可以在碎片被销毁时正确地保存其实例,在碎片被重建时将其还原到前一个状态. 1.使用上一篇的项目Fragments,在Fragment1.java文件中添加如下代码: package net.zenail.Fragments; import android.app.Activity; import android.os.Bundle; import android.support.v4.app.Fragm

android Listview分批加载+自动加载(附源码下载)

直接上代码,代码有注释: public class TestForListviewActivity extends Activity implements OnScrollListener { private ListView mListview = null; private View mFooterView; private PaginationAdapter mAdapter; private Handler handler=new Handler(); private boolean i

Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)

Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载) POSTED ON 2014年6月27日 BY 天边的星星 本文内容: 1.横向ListView的所有实现思路; 2.其中一个最通用的思路HorizontalListView,并基于横向ListView开发一个简单的相册: 3.实现的横向ListView在点击.浏览时item背景会变色,并解决了listview里setSelected造成item的选择状态混乱的问题.

Android中Loader及LoaderManager的使用(附源码下载)

managedQuery方法的缺陷 Loader是用来更好地加载数据的,在我们谈论Loader之前,我们先研究一下Activity的managedQuery方法,该方法也是用于在Activity中加载数据的.在Android 3.0之前的版本中,我们如果想在Activity中通过ContentResolver对ContentProvider进行查询,我们可以方便的调用Activity的managedQuery方法,该方法的源码如下: @Deprecated public final Cursor

Android 音视频深入 六 使用FFmpeg播放视频(附源码下载)

本篇项目地址,求starhttps://github.com/979451341/Audio-and-video-learning-materials/tree/master/FFmpeg%E6%92%AD%E6%94%BE%E8%A7%86%E9%A2%91 首先FFmpeg是c语言写的,所以我们需要NDK的技术,然后我使用的NDK使用Cmake的,一开始就是说如何将FFmpeg导入项目,使用我的方法导入FFmpeg不用一分钟. 这个需要大家先在上面的代码地址里下载项目代码因为FFmpeg这个

Android 音视频深入 十一 FFmpeg和AudioTrack播放声音(附源码下载)

项目地址,求starhttps://github.com/979451341/AudioVideoStudyCodeTwo/tree/master/FFmpeg%E6%92%AD%E6%94%BE%E9%9F%B3%E4%B9%90%EF%BC%88%E4%BF%9D%E7%A8%8B%E5%BA%8F%E4%B8%8D%E6%AD%BB%EF%BC%89 这个是FFmpeg解码出音频,给AudioTrack播放,这回才算是java与c语言之间合作 这回我们将会从c++里调用java函数,下面就

Android 音视频深入 十六 FFmpeg 推流手机摄像头,实现直播 (附源码下载)

源码地址https://github.com/979451341/RtmpCamera/tree/master 配置RMTP服务器,虽然之前说了,这里就直接粘贴过来吧 1.配置RTMP服务器 这个我不多说贴两个博客分别是在mac和windows环境上的,大家跟着弄MAC搭建RTMP服务器https://www.jianshu.com/p/6fcec3b9d644这个是在windows上的,RTMP服务器搭建(crtmpserver和nginx) https://www.jianshu.com/p