android videoview 截屏,ijkplayer开启rtsp,并且支持录制和截图功能

* author:lebonbill

* E-mail:lebonbillwu@gmail.com

ijkplayer框架

ijkplayer 是B站开源的一款做视频直播的播放器框架, 基于ffmpeg, 支持 Android 和 iOS,git地址是:https://github.com/Bilibili/ijkplayer.git

编译之前

之前用Cygwin编译,各种坑,建议还是用ubuntu编译会方便很多,我是在windows8跑vmware虚拟ubuntu来编译的.首先git获取ijkplayer的源代码,然后还需要配置环境变量Android SDK和Android NDK

# add these lines to your ~/.bash_profile or ~/.profile

# export ANDROID_SDK=

# export ANDROID_NDK=

开启支持RTSP

开启支持RTSP,默认不支持RTSP,需要修改module-lite.sh内容,新增对应的协议,module-lite.sh是在config目录下

export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtp"

export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=rtsp"

export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=mjpeg"

export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mjpeg"

然后修改支持module-lite.sh

cd config

rm module.sh

ln -s module-lite.sh module.sh

添加录制+截图功能

在编译之前如果想实现实现录制和截图功能的话可以看这里,不需要可以忽略跳过。由于是基于FFMpeg,新增startRecord(开始录播),stopRecord(通知录制),和截图都需要修改FFMpeg的源码,所以找到ijkplayer-android/ijkmedia/ijkplayer目录下的ff_ffplay.h,新增三个方法

int ffp_start_record(FFPlayer *ffp, const char *file_name);

int ffp_stop_record(FFPlayer *ffp);

int ffp_record_file(FFPlayer *ffp, AVPacket *packet);

void ffp_get_current_frame_l(FFPlayer *ffp, uint8_t *frame_buf);

修改ff_ffplay.c

* 开始录制函数:file_name是保存路径

int ffp_start_record(FFPlayer *ffp, const char *file_name)

{

assert(ffp);

VideoState *is = ffp->is;

ffp->m_ofmt_ctx = NULL;

ffp->m_ofmt = NULL;

ffp->is_record = 0;

ffp->record_error = 0;

if (!file_name || !strlen(file_name)) { // 没有路径

av_log(ffp, AV_LOG_ERROR, "filename is invalid");

goto end;

}

if (!is || !is->ic|| is->paused || is->abort_request) { // 没有上下文,或者上下文已经停止

av_log(ffp, AV_LOG_ERROR, "is,is->ic,is->paused is invalid");

goto end;

}

if (ffp->is_record) { // 已经在录制

av_log(ffp, AV_LOG_ERROR, "recording has started");

goto end;

}

// 初始化一个用于输出的AVFormatContext结构体

avformat_alloc_output_context2(&ffp->m_ofmt_ctx, NULL, "mp4", file_name);

if (!ffp->m_ofmt_ctx) {

av_log(ffp, AV_LOG_ERROR, "Could not create output context filename is %s\n", file_name);

goto end;

}

ffp->m_ofmt = ffp->m_ofmt_ctx->oformat;

for (int i = 0; i < is->ic->nb_streams; i++) {

// 对照输入流创建输出流通道

AVStream *in_stream = is->ic->streams[i];

AVStream *out_stream = avformat_new_stream(ffp->m_ofmt_ctx, in_stream->codec->codec);

if (!out_stream) {

av_log(ffp, AV_LOG_ERROR, "Failed allocating output stream\n");

goto end;

}

// 将输入视频/音频的参数拷贝至输出视频/音频的AVCodecContext结构体

av_log(ffp, AV_LOG_DEBUG, "in_stream->codec;%@\n", in_stream->codec);

if (avcodec_copy_context(out_stream->codec, in_stream->codec) < 0) {

av_log(ffp, AV_LOG_ERROR, "Failed to copy context from input to output stream codec context\n");

goto end;

}

out_stream->codec->codec_tag = 0;

if (ffp->m_ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {

out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;

}

}

av_dump_format(ffp->m_ofmt_ctx, 0, file_name, 1);

// 打开输出文件

if (!(ffp->m_ofmt->flags & AVFMT_NOFILE)) {

if (avio_open(&ffp->m_ofmt_ctx->pb, file_name, AVIO_FLAG_WRITE) < 0) {

av_log(ffp, AV_LOG_ERROR, "Could not open output file '%s'", file_name);

goto end;

}

}

// 写视频文件头

if (avformat_write_header(ffp->m_ofmt_ctx, NULL) < 0) {

av_log(ffp, AV_LOG_ERROR, "Error occurred when opening output file\n");

goto end;

}

ffp->is_record = 1;

ffp->record_error = 0;

pthread_mutex_init(&ffp->record_mutex, NULL);

return 0;

end:

ffp->record_error = 1;

return -1;

}

*停止录播

int ffp_stop_record(FFPlayer *ffp)

{

assert(ffp);

if (ffp->is_record) {

ffp->is_record = 0;

pthread_mutex_lock(&ffp->record_mutex);

if (ffp->m_ofmt_ctx != NULL) {

av_write_trailer(ffp->m_ofmt_ctx);

if (ffp->m_ofmt_ctx && !(ffp->m_ofmt->flags & AVFMT_NOFILE)) {

avio_close(ffp->m_ofmt_ctx->pb);

}

avformat_free_context(ffp->m_ofmt_ctx);

ffp->m_ofmt_ctx = NULL;

ffp->is_first = 0;

}

pthread_mutex_unlock(&ffp->record_mutex);

pthread_mutex_destroy(&ffp->record_mutex);

av_log(ffp, AV_LOG_DEBUG, "stopRecord ok\n");

} else {

av_log(ffp, AV_LOG_ERROR, "don't need stopRecord\n");

}

return 0;

}

*保存文件

int ffp_stop_record(FFPlayer *ffp)

{

assert(ffp);

if (ffp->is_record) {

ffp->is_record = 0;

pthread_mutex_lock(&ffp->record_mutex);

if (ffp->m_ofmt_ctx != NULL) {

av_write_trailer(ffp->m_ofmt_ctx);

if (ffp->m_ofmt_ctx && !(ffp->m_ofmt->flags & AVFMT_NOFILE)) {

avio_close(ffp->m_ofmt_ctx->pb);

}

avformat_free_context(ffp->m_ofmt_ctx);

ffp->m_ofmt_ctx = NULL;

ffp->is_first = 0;

}

pthread_mutex_unlock(&ffp->record_mutex);

pthread_mutex_destroy(&ffp->record_mute

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android中的VideoView是一个用于播放视频的视图控件,支持播放网络上的视频内容。RTSP(Real-Time Streaming Protocol)是一种实时流媒体传输协议,用于在网络上传输音视频数据。 要在Android中使用VideoView播放RTSP视频,需要进行以下步骤: 1. 在布局文件中添加VideoView控件: ``` <VideoView android:id="@+id/videoView" android:layout_width="match_parent" android:layout_height="wrap_content" /> ``` 2. 在Java代码中找到VideoView控件并设置其播放的视频路径: ``` VideoView videoView = findViewById(R.id.videoView); String videoUrl = "rtsp://example.com/video"; videoView.setVideoURI(Uri.parse(videoUrl)); ``` 3. 增加网络访问权限和音视频播放权限: ``` <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> ``` 4. 控制视频的播放和停止: ``` videoView.start(); // 开始播放 videoView.pause(); // 暂停播放 videoView.stopPlayback(); // 停止播放 ``` 需要注意的是,RTSP视频的播放可能受到网络速度和服务器支持等因素的影响,如果遇到播放问题,可以尝试改用其他播放方式或检查网络连接。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值