package com.live.muxer;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.util.Log;
import com.live.simplertmp.DefaultRtmpPublisher;
import com.live.simplertmp.RtmpHandler;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 主要对视音频原始数据h264和aac数据进行flv tag格式的封装,然后将封装好的数据传递给rtmp模块进行推理发送
* Created by winlin on 5/2/15.
* Updated by leoma on 4/1/16.
* to POST the h.264/avc annexb frame over RTMP.
* @see android.media.MediaMuxer https://developer.android.com/reference/android/media/MediaMuxer.html
*/
public class SrsFlvMuxer {
private static final int VIDEO_ALLOC_SIZE = 128 * 1024; //
private static final int AUDIO_ALLOC_SIZE = 4 * 1024;
private volatile boolean started = false;
private DefaultRtmpPublisher publisher;
private Thread worker;
private final Object txFrameLock = new Object();
private SrsFlv flv = new SrsFlv(); //flv格式封装相关
private boolean needToFindKeyFrame = true;
private SrsFlvFrame mVideoSequenceHeader; //视频头帧
private SrsFlvFrame mAudioSequenceHeader; //音频头帧
private SrsAllocator mVideoAllocator = new SrsAllocator(VIDEO_ALLOC_SIZE);
private SrsAllocator mAudioAllocator = new SrsAllocator(AUDIO_ALLOC_SIZE);
//ConcurrentLinkedQueue是一个基于链表的无界非阻塞队列,并且是线程安全的,它采用的是先进先出的规则,当我们增加一个元素时,
// 它会添加到队列的末尾,当我们取一个元素时,它会返回一个队列头部的元素,用来实现高并发的一个队列
private ConcurrentLinkedQueue<SrsFlvFrame> mFlvTagCache = new ConcurrentLinkedQueue<>();
private static final int VIDEO_TRACK = 100;
private static final int AUDIO_TRACK = 101;
private static final String TAG = "SrsFlvMuxer";
/**
* constructor.
* @param handler the rtmp event handler.
*/
public SrsFlvMuxer(RtmpHandler handler) {
publisher = new DefaultRtmpPublisher(handler);
}
/**
* get cached video frame number in publisher
*/
public AtomicInteger getVideoFrameCacheNumber() {
return publisher == null ? null : publisher.getVideoFrameCacheNumber();
}
/**
* set video resolution for publisher
* @param width width
* @param height height
*/
public void setVideoResolution(int width, int height) {
if (publisher != null) {
publisher.setVideoResolution(width, height);
}
}
/**
* Adds a track with the specified format.
* @param format The media format for the track.
* @return The track index for this newly added track.
*/
public int addTrack(MediaFormat format) {
if (format.getString(MediaFormat.KEY_MIME).contentEquals("video/avc")) {
flv.setVideoTrack(format);
return VIDEO_TRACK;
} else {
flv.setAudioTrack(format);
return AUDIO_TRACK;
}
}
//rtmp断开连接
private void disconnect() {
try {
publisher.close();
} catch (IllegalStateException e) {
// Ignore illegal state.
}
mVideoSequenceHeader = null;
mAudioSequenceHeader = null;
Log.i(TAG, "worker: disconnect ok.");
}
private boolean connect(String url) {
boolean connected = false;
Log.i(TAG, String.format("worker: connecting to RTMP server by url=%s\n", url));
if (publisher.connect(url)) {
connected = publisher.publish("live");
}
mVideoSequenceHeader = null;
mAudioSequenceHeader = null;
return connected;
}
//通过publisher推送flv Tag数据
private void sendFlvTag(SrsFlvFrame frame) {
if (frame == null) {
return;
}
if (frame.isVideo()) {
if (frame.isKeyFrame()) {
Log.i(TAG, String.format("worker: send frame type=%d, dts=%d, size=%dB",
frame.type, frame.dts, frame.flvTag.array().length));
}
publisher.publishVideoData(frame.flvTag.array(), frame.flvTag.size(), frame.dts);
mVideoAllocator.release(frame.flvTag);
} else if (frame.isAudio()) {
publisher.publishAudioData(frame.flvTag.array(), frame.flvTag.size(), frame.dts);
mAudioAllocator.release(frame.flvTag);
}
}
/**
* start to the remote server for remux.
*/
public void start(final String rtmpUrl) {
started = true;
worker = new Thread(new Runnable() {
@Override
public void run() {
//连接url
if (!connect(rtmpUrl)) {
return;
}
while (!Thread.interrupted()) {
//循环从缓冲中取数据,因为是非阻塞队列,所以要先判断是否为空
while (!mFlvTagCache.isEmpty()) {
//如果队列为空,则返回null
SrsFlvFrame frame = mFlvTagCache.poll();
if (frame.isSequenceHeader()) {
if (frame.isVideo()) {
mVideoSequenceHeader = frame;
sendFlvTag(mVideoSequenceHeader);
} else if (frame.isAudio()) {
mAudioSequenceHeader = frame;
sendFlvTag(mAudioSequenceHeader);
}
} else {
if (frame.isVideo() && mVideoSequenceHeader != null) {
sendFlvTag(frame);
} else if (frame.isAudio() && mAudioSequenceHeader != null) {
sendFlvTag(frame);
}
}
}
// Waiting for next frame
synchronized (txFrameLock) {
try {
// isEmpty() may take some time, so we set timeout to detect next frame
txFrameLock.wait(500);
} catch (InterruptedException ie) {
worker.interrupt();
}
}
}
}
});
worker.start();
}
/**
* stop the muxer, disconnect RTMP connection.
*/
public void stop() {
started = false;
mFlvTagCache.clear();
if (worker != null) {
worker.interrupt();
try {
worker.join();
} catch (InterruptedException e) {
e.printStackTrace();
worker.interrupt();
}
worker = null;
}
flv.reset();
needToFindKeyFrame = true;
Log.i(TAG, "SrsFlvMuxer closed");
// We should not block the main thread
new Thread(new Runnable() {
@Override
public void run() {
disconnect();
}
}).start();
}
/**
* send the annexb frame over RTMP.
* @param trackIndex The track index for this sample.
* @param byteBuf The encoded sample.
* @param bufferInfo The buffer information related to this sample.
*/
public void writeSampleData(int trackIndex, ByteBuffer byteBuf, MediaCodec.BufferInfo bufferInfo) {
if (bufferInfo.offset > 0) {
Log.w(TAG, String.format("encoded frame %dB, offset=%d pts=%dms",
bufferInfo.size, bufferInfo.offset, bufferInfo.presentationTimeUs / 1000
));
}
if (VIDEO_TRACK == trackIndex) {
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
C和C++开发基于FFmpeg和OpenGL的视频播放器项目源码.zipC和C++开发基于FFmpeg和OpenGL的视频播放器项目源码.zipC和C++开发基于FFmpeg和OpenGL的视频播放器项目源码.zipC和C++开发基于FFmpeg和OpenGL的视频播放器项目源码.zipC和C++开发基于FFmpeg和OpenGL的视频播放器项目源码.zipC和C++开发基于FFmpeg和OpenGL的视频播放器项目源码.zipC和C++开发基于FFmpeg和OpenGL的视频播放器项目源码.zip 【资源说明】 适用人群:该项目属于高分优质项目,上传之前都本地运行验证过。适合小白、高校学生、教师、科研人员、公司员工下载学习借鉴使用。 用途:学习借鉴,也可在此基础上二次开发,当然也可以直接用于课设、作业、毕设、实际项目等。 技术支持:关于项目的技术细节或更详细的介绍,可以私信与我沟通,或看项目内的项目说明(若有)、代码等,很乐意交流学习。 【特别强调】 若自己基础实在太差,自己不懂运行,可以与我私聊,可远程教学指导。当然也可以做项目二次开发和定制。
资源推荐
资源详情
资源评论
收起资源包目录
C和C++开发基于FFmpeg和OpenGL的视频播放器项目源码.zip (2000个子文件)
libfdk-aac.a 6.87MB
libfdk-aac.a 6.87MB
libyuv.a 2.18MB
libyuv.a 2.18MB
libx264.a 1.12MB
libx264.a 1.12MB
librtmp.a 81KB
librtmp.a 81KB
gradlew.bat 2KB
gradlew.bat 2KB
WavReader.c 5KB
WavReader.c 5KB
MediaPlayer.cpp 42KB
MediaPlayer.cpp 42KB
TDStretch.cpp 35KB
TDStretch.cpp 35KB
com.eplayer.EasyMediaPlayer.cpp 27KB
com.eplayer.EasyMediaPlayer.cpp 27KB
MediaMetadataRetriever.cpp 26KB
MediaMetadataRetriever.cpp 26KB
com_live_LiveNativeManager.cpp 25KB
com_live_LiveNativeManager.cpp 25KB
MediaSync.cpp 22KB
MediaSync.cpp 22KB
RtmpLivePush.cpp 20KB
RtmpLivePush.cpp 20KB
VideoEncoder.cpp 18KB
VideoEncoder.cpp 18KB
com_eplayer_EMeiaMetadataRetriever.cpp 17KB
com_eplayer_EMeiaMetadataRetriever.cpp 17KB
SoundTouch.cpp 17KB
SoundTouch.cpp 17KB
AudioResampler.cpp 16KB
AudioResampler.cpp 16KB
SLESDevice.cpp 15KB
SLESDevice.cpp 15KB
EMediaPlayer.cpp 14KB
EMediaPlayer.cpp 14KB
mmx_optimized.cpp 13KB
mmx_optimized.cpp 13KB
sse_optimized.cpp 13KB
sse_optimized.cpp 13KB
GLESDevice.cpp 12KB
GLESDevice.cpp 12KB
AudioEncoder.cpp 12KB
AudioEncoder.cpp 12KB
JNIHelp.cpp 11KB
JNIHelp.cpp 11KB
vecmath.cpp 10KB
vecmath.cpp 10KB
BPMDetect.cpp 10KB
BPMDetect.cpp 10KB
OpenGLUtils.cpp 10KB
OpenGLUtils.cpp 10KB
FIRFilter.cpp 10KB
FIRFilter.cpp 10KB
glm.cpp 9KB
glm.cpp 9KB
GLInputYUV420PFilter.cpp 9KB
GLInputYUV420PFilter.cpp 9KB
YuvUtil.cpp 9KB
YuvUtil.cpp 9KB
FIFOSampleBuffer.cpp 8KB
FIFOSampleBuffer.cpp 8KB
PeakFinder.cpp 8KB
PeakFinder.cpp 8KB
Metadata.cpp 8KB
Metadata.cpp 8KB
RateTransposer.cpp 8KB
RateTransposer.cpp 8KB
InterpolateLinear.cpp 8KB
InterpolateLinear.cpp 8KB
RenderNodeList.cpp 8KB
RenderNodeList.cpp 8KB
EglHelper.cpp 7KB
EglHelper.cpp 7KB
dummy.cpp 7KB
dummy.cpp 7KB
VideoDecoder.cpp 7KB
VideoDecoder.cpp 7KB
AAFilter.cpp 6KB
AAFilter.cpp 6KB
InterpolateCubic.cpp 6KB
InterpolateCubic.cpp 6KB
FFmpegUtils.cpp 6KB
FFmpegUtils.cpp 6KB
PlayerState.cpp 6KB
PlayerState.cpp 6KB
GLFilter.cpp 6KB
GLFilter.cpp 6KB
YuvProcess.cpp 6KB
YuvProcess.cpp 6KB
CoordinateUtils.cpp 6KB
CoordinateUtils.cpp 6KB
InterpolateShannon.cpp 6KB
InterpolateShannon.cpp 6KB
AVQueue.cpp 5KB
AVQueue.cpp 5KB
FilterManager.cpp 5KB
FilterManager.cpp 5KB
共 2000 条
- 1
- 2
- 3
- 4
- 5
- 6
- 20
资源评论
Scikit-learn
- 粉丝: 4891
- 资源: 3184
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 升降式载具供料机sw18可编辑全套技术资料100%好用.zip
- 无刷直流电机 BLDC三闭环控制(包括位置环,速度环,电流环 )Matlab simulink仿真搭建模型: 提供以下帮助 波形纪录 参考文献 仿真文件 原理解释 电机参数说明 仿真原理结构和整体框图
- COMSOL 激光 激光熔覆 名称:激光熔覆 适用人群:激光研究人员 工程师 服务:模型+视频教程
- 类比于同步电机VSG所提出的直流电机VDG,可以很好地抑制负荷波动而引起的电压不稳定,提升了系统稳定性 其核心就是在DC-DC闭环控制基础上加入了机械方程与电枢回路方程 直流侧400V,输出侧75
- 钢轨表面缺陷检测数据集 总共400张图片,8种类别缺陷 txt格式,可用于目标检测
- 双机械手抓料激光打码出料机sw18可编辑全套技术资料100%好用.zip
- 双工位激光焊接设备sw17全套技术资料100%好用.zip
- 双三相电机(六相电机模型) 双dq和vsd Matlab simulink仿真模型电机控制 电机控制
- zed-windows 0.166.1 编辑器
- oled-i2c实验-源码
- Delphi 12 控件之XLSReadWriteII v6.02.01-INSTALL.txt
- 深度强化学习应用于股票市场高频和低频交易的实现与评估-复现论文
- 一款自动化养鸡笼具的笼体sw17可编辑全套技术资料100%好用.zip
- Delphi 12 控件之RAD Studio 12 x64 Release 设置.txt
- 基于PLC全自动洗衣机控制系统设计 含Word文档一整套 前 言\\t1 第一章 绪 论\\t2 第一节 研究背景研究目的和意义\\t2 第二节 国内外发展现状\\t2 第三节 主要研究
- MVC-内部培训 M Visual Components工业仿真平台的应用与实践
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功