您的位置:首页 > 移动开发 > Android开发

Android 基于FFMpeg命令的转流器

2017-03-14 17:03 323 查看
目前市场上的流行的摄像头都是视频流都是rtsp协议的,而目前的流媒体的服务器推流都是使用rmtp协议,这是需要把一个rtsp的视频流转成rtmp的视频流,牛人可以自己写一个拉流器和推流器,自己来实现,对于刚涉及到这个领域的人来说可以考虑使用目前很流行,且很牛B的开源框架来实现,它就是大名鼎鼎的FFMpeg,至于它如何的牛,百度一下,目前播放器里都有它的身影,比如要实现把rtsp转rtmp只需要一个行命令就行“ffmpeg -re -i rtsp://192.168.191.3/mpeg4cif -vcodec
copy -acodec copy -f flv -y rtmp://www.ossrs.net/live/helloworld”,这个命令的意思就是把视频流从192.168.191.3拉下来,然后视频编码与音频编码复用,打包成flv格式的文件流推送到www.ossrs.net的流媒体服务器上去。

但这个框架是使用C语言编写的,android上如何迁移呢,对于新手来说,把这个C框架迁移到android平台也是个麻烦,但这个问题已经被解决了,目前只需要加一行包依赖就可以让你的应用使用上FFmpeg,目前已经有一些开源项目做这个事情,http://writingminds.github.io/ffmpeg-android-java/

先在你的android 加上一行依赖

Grab via gradle
compile 'com.writingminds:FFmpegAndroid:0.3.2'


Or Maven
<dependency>
<groupId>com.writingminds</groupId>
<artifactId>FFmpegAndroid</artifactId>
<version>0.3.2</version>
</dependency>


下面的代码就是基于ffmpeg的命令的转流器实现

emptypackage com.foresee.wificamera.service.impl;

import android.content.Context;
import android.util.Log;

import com.foresee.wificamera.service.LivePusher;
import com.github.hiteshsondhi88.libffmpeg.ExecuteBinaryResponseHandler;
import com.github.hiteshsondhi88.libffmpeg.FFmpeg;
import com.github.hiteshsondhi88.libffmpeg.LoadBinaryResponseHandler;
import com.github.hiteshsondhi88.libffmpeg.exceptions.FFmpegCommandAlreadyRunningException;
import com.github.hiteshsondhi88.libffmpeg.exceptions.FFmpegNotSupportedException;

import java.util.regex.Pattern;

/**
* 使用FFMPEG进行推流的推流器
* Created by Administrator on 2017-03-14.
*/

public class FFmpegLivePusher implements LivePusher {

private static final String LOG_TAG = "FFmpegLivePusher";
private static final String FFMPEG_PUSH_COMMAND_PATTERN = "-re -i %s -vcodec copy -acodec copy -f flv -y %s";
private String inputURI;
private String outputURI;

private Context context;
private FFmpeg ffmpeg;
private boolean stopFlag = false;
private int rescueNum = 0;
private boolean pushErrorFlag = false;
private final Pattern pattern = Pattern.compile("frame=(\\s*\\w*\\s)fps=(\\s*\\w*\\s*)");

public FFmpegLivePusher(Context _context, String _inputURI, String _outputURI) throws FFmpegNotSupportedException {
this.inputURI = _inputURI;
this.outputURI = _outputURI;
this.context = _context;

ffmpeg = FFmpeg.getInstance(context);

ffmpeg.loadBinary(new LoadBinaryResponseHandler(){
@Override
public void onFailure() {
Log.e(LOG_TAG, "加载FFmpeg出错!");
ffmpeg = null;
}

@Override
public void onFinish() {
Log.i(LOG_TAG, "load FFmpeg success!");

}
});

}

@Override
public void startPush() {
if(ffmpeg != null){

String[] commands = String.format(FFMPEG_PUSH_COMMAND_PATTERN,
inputURI, outputURI).split(" ");

if(ffmpeg.isFFmpegCommandRunning()){
ffmpeg.killRunningProcesses();
}

try {
ffmpeg.execute(commands, new ExecuteBinaryResponseHandler(){

@Override
public void onProgress(String message) {
Log.i(LOG_TAG, message);
//根据输出特定的日志来判断是否在推流
if(pattern.matcher(message).find()){
//说明正在推流
pushErrorFlag = false;
rescueNum = 0;
}
}

@Override
public void onFailure(String message) {
Log.i(LOG_TAG, message);
pushErrorFlag = true;
}

@Override
public void onFinish() {
if(!stopFlag){
if (rescueNum < 10){
Log.e(LOG_TAG, "推流过程异常停止,重新启动推流...");
startPush();
rescueNum++;
pushErrorFlag = true;
}else{
Log.e(LOG_TAG, "推流异常停止,经抢救10次无效");
rescueNum = 0;
pushErrorFlag = true;
}

}
}
});
} catch (FFmpegCommandAlreadyRunningException e) {
e.printStackTrace();
}
}
}

@Override
public void stopPush() {
stopFlag = true;
if(ffmpeg.isFFmpegCommandRunning()){
ffmpeg.killRunningProcesses();
}
}

public boolean isPushError(){
return pushErrorFlag;
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android ffmpeg