bilibili可不可以摄像头直播和ipad录屏直播bilibili同时进行啊?就是录屏下面再有一

俊吹本吹 陈圣俊全世界最可爱 (什么都被版权崩溃了??? 起名起到奔溃不行就是不行哭了
<option value='/video/av/index_1.html' cid='、7.17
<option value='/video/av/index_2.html' cid='、7.17(1)
<option value='/video/av/index_3.html' cid='、7.17(2)
视频地址复制
Flash地址复制
Html地址复制
离线看更方便
用或其他应用扫描二维码
没有摄像头!从下午开始播的 播到了七点左右
是从下午两点半开始录的。。
1p呢是录一半突然断了 然后接着2P到主播去吃饭的!
3p是主播吃饭回来开始然后开始的!
主播没有洗头哦 但是没有摄像头的主播也超可爱啦
话痨一个了哈哈哈!
(怕他明天又突然直播今天赶紧上传!!)
广播电视节目制作经营许可证:(沪)字第1248号
| 网络文化经营许可证:沪网文[6号 | 信息网络传播视听节目许可证:0910417 | 互联网ICP备案:沪ICP备号-3 沪ICP证:沪B2- | 违法不良信息举报邮箱: | 违法不良信息举报电话:转3你的位置:///bilibili直播姬
相关软件下载
哔哩哔哩直播姬(bilibili直播)是由哔哩哔哩官方自主研发的手机直播助手,让你何时何地都能开启美妙的二次元直播之旅。
bilibili直播姬官网介绍
bilibili直播姬简称blink,坊间亦称之为bilibili live in new kosmos(哔哩哔哩在新世界的生活),是直播姬的进化体,集IM群组功能、短视频、直播功能于一体。通过blink,不但可以使用直播、短视频的功能,更可以直接通过应援团群组功能与你的&爱抖露&进行联系哦!
bilibili直播姬主要功能
一键直播:登录你的B站账号,选择摄像头或者录屏直播,开启你的直播之旅。
bilibili直播姬更新内容
【优化】提升了稳定性,修复了一些BUG;
标签聚合:
bilibili直播姬下载地址
相关专题推荐
相关教程资讯
客官,请随便说两句
本类下载排行榜"ios录屏直播软件哪个好"的糗事
你可能感兴趣:
糗事百科为大家收集了很多的ios录屏直播软件哪个好的糗事,各种关于ios录屏直播软件哪个好的爆笑经历、尴尬时刻和开心视频,想持续关注ios录屏直播软件哪个好的糗事就收藏本页吧.10083人阅读
Android(18)
图像/流媒体(5)
应项目需求瞄准了Bilibili的录屏直播功能,基本就仿着做一个吧。研究后发现Bilibili是使用的MediaProjection 与 VirtualDisplay结合实现的,需要 Android 5.0 Lollipop API 21以上的系统才能使用。
其实官方提供的这个Sample中已经有了MediaRecorder的实现与使用方式,还有使用MediaRecorder实现的录制屏幕到本地文件的Demo,从中我们都能了解这些API的使用。
而如果需要直播推流的话就需要自定义MediaCodec,再从MediaCodec进行编码后获取编码后的帧,免去了我们进行原始帧的采集的步骤省了不少事。可是问题来了,因为之前没有仔细了解H264文件的结构与FLV封装的相关技术,其中爬了不少坑,此后我会一一记录下来,希望对用到的朋友有帮助。
项目中对我参考意义最大的一个Demo是网友Yrom的GitHub项目,Demo中实现了录屏并将视频流存为本地的MP4文件(咳咳,其实Yrom就是Bilibili的员工吧?( ゜- ゜)つロ)??。在此先大致分析一下该Demo的实现,之后我会再说明我的实现方式。
具体的原理在Demo的README中已经说得很明白了:
Display&可以“投影”到一个&VirtualDisplay
通过&MediaProjectionManager&取得的&MediaProjection创建VirtualDisplay
VirtualDisplay&会将图像渲染到&Surface中,而这个Surface是由MediaCodec所创建的
mEncoder = MediaCodec.createEncoderByType(MIME_TYPE);
mSurface = mEncoder.createInputSurface();
mVirtualDisplay = mMediaProjection.createVirtualDisplay(name, mWidth, mHeight, mDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, mSurface, null, null);
MediaMuxer&将从&MediaCodec&得到的图像元数据封装并输出到MP4文件中
int index = mEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_US);
ByteBuffer encodedData = mEncoder.getOutputBuffer(index);
mMuxer.writeSampleData(mVideoTrackIndex, encodedData, mBufferInfo);
所以其实在Android 4.4上可以通过DisplayManager来创建VirtualDisplay也是可以实现录屏,但因为权限限制需要ROOT。 (see&)
Demo很简单,两个Java文件:
MainActivity.java
ScreenRecorder.java
MainActivity
类中仅仅是实现的入口,最重要的方法是onActivityResult,因为MediaProjection就需要从该方法开启。但是别忘了先进行MediaProjectionManager的初始化
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
MediaProjection mediaProjection = mMediaProjectionManager.getMediaProjection(resultCode, data);
if (mediaProjection == null) {
Log.e("@@", "media projection is null");
final int width = 1280;
final int height = 720;
File file = new File(Environment.getExternalStorageDirectory(),
"record-" + width + "x" + height + "-" + System.currentTimeMillis() + ".mp4");
final int bitrate = 6000000;
mRecorder = new ScreenRecorder(width, height, bitrate, 1, mediaProjection, file.getAbsolutePath());
mRecorder.start();
mButton.setText("Stop Recorder");
Toast.makeText(this, "Screen recorder is running...", Toast.LENGTH_SHORT).show();
moveTaskToBack(true);
ScreenRecorder
这是一个线程,结构很清晰,run()方法中完成了MediaCodec的初始化,VirtualDisplay的创建,以及循环进行编码的全部实现。
public void run() {
prepareEncoder();
mMuxer = new MediaMuxer(mDstPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
} catch (IOException e) {
throw new RuntimeException(e);
mVirtualDisplay = mMediaProjection.createVirtualDisplay(TAG + "-display",
mWidth, mHeight, mDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
mSurface, null, null);
Log.d(TAG, "created virtual display: " + mVirtualDisplay);
recordVirtualDisplay();
} finally {
release();
MediaCodec的初始化
方法中进行了编码器的参数配置与启动、Surface的创建两个关键的步骤
private void prepareEncoder() throws IOException {
MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
format.setInteger(MediaFormat.KEY_BIT_RATE, mBitRate);
format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
Log.d(TAG, "created video format: " + format);
mEncoder = MediaCodec.createEncoderByType(MIME_TYPE);
mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mSurface = mEncoder.createInputSurface();
Log.d(TAG, "created input surface: " + mSurface);
mEncoder.start();
编码器实现循环编码
下面的代码就是编码过程,由于作者使用的是Muxer来进行视频的采集,所以在resetOutputFormat方法中实际意义是将编码后的视频参数信息传递给Muxer并启动Muxer。
private void recordVirtualDisplay() {
while (!mQuit.get()) {
int index = mEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_US);
Log.i(TAG, "dequeue output buffer index=" + index);
if (index == _OUTPUT_FORMAT_CHANGED) {
resetOutputFormat();
} else if (index == _TRY_AGAIN_LATER) {
Log.d(TAG, "retrieving buffers time out!");
Thread.sleep(10);
} catch (InterruptedException e) {
} else if (index &= 0) {
if (!mMuxerStarted) {
throw new IllegalStateException("MediaMuxer dose not call addTrack(format) ");
encodeToVideoTrack(index);
mEncoder.releaseOutputBuffer(index, false);
private void resetOutputFormat() {
if (mMuxerStarted) {
throw new IllegalStateException("output format already changed!");
MediaFormat newFormat = mEncoder.getOutputFormat();
Log.i(TAG, "output format changed.\n new format: " + newFormat.toString());
mVideoTrackIndex = mMuxer.addTrack(newFormat);
mMuxer.start();
mMuxerStarted = true;
Log.i(TAG, "started media muxer, videoIndex=" + mVideoTrackIndex);
获取sps pps的ByteBuffer,注意此处的sps pps都是read-only只读状态
private void getSpsPpsByteBuffer(MediaFormat newFormat) {
ByteBuffer rawSps = newFormat.getByteBuffer("csd-0");
ByteBuffer rawPps = newFormat.getByteBuffer("csd-1");
录屏视频帧的编码过程
BufferInfo.flags表示当前编码的信息,如源码注释:
* This indicates that the (encoded) buffer marked as such contains
* the data for a key frame.
public static final int BUFFER_FLAG_KEY_FRAME = 1;
* This indicated that the buffer marked as such contains codec
* initialization / codec specific data instead of media data.
public static final int BUFFER_FLAG_CODEC_CONFIG = 2;
* This signals the end of stream, i.e. no buffers will be available
* after this, unless of course, {@link #flush} follows.
public static final int BUFFER_FLAG_END_OF_STREAM = 4;
实现编码:
private void encodeToVideoTrack(int index) {
ByteBuffer encodedData = mEncoder.getOutputBuffer(index);
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
Log.d(TAG, "ignoring BUFFER_FLAG_CODEC_CONFIG");
mBufferInfo.size = 0;
if (mBufferInfo.size == 0) {
Log.d(TAG, "info.size == 0, drop it.");
encodedData = null;
Log.d(TAG, "got buffer, info: size=" + mBufferInfo.size
+ ", presentationTimeUs=" + mBufferInfo.presentationTimeUs
+ ", offset=" + mBufferInfo.offset);
if (encodedData != null) {
encodedData.position(mBufferInfo.offset);
encodedData.limit(mBufferInfo.offset + mBufferInfo.size);
mMuxer.writeSampleData(mVideoTrackIndex, encodedData, mBufferInfo);
Log.i(TAG, "sent " + mBufferInfo.size + " bytes to muxer...");
以上就是对ScreenRecorder这个Demo的大体分析,由于总结时间仓促,很多细节部分我也没有进行深入的发掘研究,所以请大家抱着怀疑的态度阅读,如果说明有误或是理解不到位的地方,希望大家帮忙指出,谢谢!
在功能的开发中还参考了很多有价值的资料与文章:
后续更新…
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:66600次
排名:千里之外
原创:52篇
转载:13篇
评论:63条
阅读:15544
阅读:3269
阅读:1808
(1)(2)(1)(3)(7)(3)(5)(5)(6)(30)(1)(1)广播电视节目制作经营许可证:(沪)字第1248号
| 网络文化经营许可证:沪网文[6号 | 信息网络传播视听节目许可证:0910417 | 互联网ICP备案:沪ICP备号-3 沪ICP证:沪B2- | 违法不良信息举报邮箱: | 违法不良信息举报电话:转3

我要回帖

更多关于 bilibililink怎么录屏 的文章

 

随机推荐