Live555 直播源 以及MediaSubsession
/*
* H264DeviceSource.hh
*
* Created on: 2014年7月19日
* Author: zjzhang
*/ #ifndef H264DEVICESOURCE_HH_
#define H264DEVICESOURCE_HH_
#include<DeviceSource.hh> class H264DeviceSource: public DeviceSource {
public:
static DeviceSource* createNew(UsageEnvironment& env,u_int8_t index=1,u_int width=352,u_int height=288,u_int fps=15,u_int kbps=100);
protected:
H264DeviceSource(UsageEnvironment& env,u_int8_t index,u_int width,u_int height,u_int fps,u_int kbps);
virtual ~H264DeviceSource();
private:
virtual void doGetNextFrame();
virtual unsigned maxFrameSize() const;
int fHeight;
int fWidth;
void *fH264Encoder;
u_int8_t * fBuffer;
u_int fBufferSize;
}; #endif /* H264DEVICESOURCE_HH_ */
/*
* H264DeviceSource.cpp
*
* Created on: 2014年7月19日
* Author: zjzhang
*/ #include "H264DeviceSource.hh"
#ifdef __cplusplus
extern "C" {
#endif
#include "H264Stream.h"
#ifdef __cplusplus
}
#endif
DeviceSource*
H264DeviceSource::createNew(UsageEnvironment& env, u_int8_t index, u_int width,
u_int height, u_int fps, u_int kbps) {
return new H264DeviceSource(env, index, width, height, fps, kbps);
} H264DeviceSource::H264DeviceSource(UsageEnvironment& env, u_int8_t index,
u_int width, u_int height, u_int fps, u_int kbps) :
DeviceSource(env, DeviceParameters()) {
openCamera(1);
getFrame(1);
fHeight = getHeight(1);
fWidth = getWidth(1);
openH264Encoder(fWidth, fHeight, fps, kbps, &fH264Encoder);
fBufferSize = fHeight * fWidth * 3 / 2;
fBuffer = new uint8_t[fBufferSize]; } H264DeviceSource::~H264DeviceSource() {
// TODO Auto-generated destructor stub delete[] fBuffer;
closeH264Encoder(fH264Encoder);
closeCamera(1);
}
unsigned H264DeviceSource::maxFrameSize() const {
// By default, this source has no maximum frame size.
return 4096;
}
void H264DeviceSource::doGetNextFrame() {
if (!isCurrentlyAwaitingData())
return; // we're not ready for the data yet unsigned char * rgbBuffer = getFrame(1);
ConvertRGB2YUV(fWidth, fHeight, rgbBuffer, fBuffer);
int newFrameSize = encodeFrame(fH264Encoder, fBuffer, fBufferSize); // Deliver the data here:
if (newFrameSize < 0) {
handleClosure();
return;
}
if (newFrameSize > fMaxSize) {
fFrameSize = fMaxSize;
fNumTruncatedBytes = newFrameSize - fMaxSize;
} else {
fFrameSize = newFrameSize;
}
if (fFrameSize > 0) {
int result = 0;
int p = 0;
do {
unsigned long len = 0;
result = getNextPacket(fH264Encoder, fBuffer + p, &len);
p += len;
} while (result > 0);
} gettimeofday(&fPresentationTime, NULL); // If you have a more accurate time - e.g., from an encoder - then use that instead.
// If the device is *not* a 'live source' (e.g., it comes instead from a file or buffer), then set "fDurationInMicroseconds" here.
memmove(fTo, fBuffer, fFrameSize); FramedSource::afterGetting(this);
}
#ifndef _DEVIC_SERVER_MEDIA_SUBSESSION_HH
#define _DEVICE_SERVER_MEDIA_SUBSESSION_HH #ifndef _ON_DEMAND_SERVER_MEDIA_SUBSESSION_HH
#include "OnDemandServerMediaSubsession.hh"
#endif
class DeviceSource;
class DeviceServerMediaSubsession: public OnDemandServerMediaSubsession {
public:
static DeviceServerMediaSubsession*
createNew(UsageEnvironment& env,
Boolean reuseFirstSource); // Used to implement "getAuxSDPLine()":
void checkForAuxSDPLine1();
void afterPlayingDummy1();
protected: // we're a virtual base class
DeviceServerMediaSubsession(UsageEnvironment& env,
Boolean reuseFirstSource);
virtual ~DeviceServerMediaSubsession(); void setDoneFlag() { fDoneFlag = ~0; } protected: // redefined virtual functions
virtual char const* getAuxSDPLine(RTPSink* rtpSink,
FramedSource* inputSource);
virtual FramedSource* createNewStreamSource(unsigned clientSessionId,
unsigned& estBitrate);
virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock,
unsigned char rtpPayloadTypeIfDynamic,
FramedSource* inputSource); private:
char* fAuxSDPLine;
char fDoneFlag; // used when setting up "fAuxSDPLine"
RTPSink* fDummyRTPSink; // ditto
}; #endif
#include "DeviceServerMediaSubsession.hh"
#include "H264VideoRTPSink.hh"
#include "DeviceSource.hh"
#include "H264VideoStreamFramer.hh"
#include "H264DeviceSource.hh" DeviceServerMediaSubsession*
DeviceServerMediaSubsession::createNew(UsageEnvironment& env,
Boolean reuseFirstSource) {
return new DeviceServerMediaSubsession(env, reuseFirstSource);
}
DeviceServerMediaSubsession::DeviceServerMediaSubsession(UsageEnvironment& env,
Boolean reuseFirstSource) :
OnDemandServerMediaSubsession(env, reuseFirstSource) {
} DeviceServerMediaSubsession::~DeviceServerMediaSubsession() {
} FramedSource* DeviceServerMediaSubsession::createNewStreamSource(
unsigned /*clientSessionId*/, unsigned& estBitrate) {
DeviceSource* source = H264DeviceSource::createNew(envir());
return H264VideoStreamFramer::createNew(envir(), source);
} RTPSink* DeviceServerMediaSubsession::createNewRTPSink(Groupsock* rtpGroupsock,
unsigned char rtpPayloadTypeIfDynamic, FramedSource* /*inputSource*/) {
return H264VideoRTPSink::createNew(envir(), rtpGroupsock,
rtpPayloadTypeIfDynamic);
} static void afterPlayingDummy(void* clientData) {
DeviceServerMediaSubsession* subsess =
(DeviceServerMediaSubsession*) clientData;
subsess->afterPlayingDummy1();
} void DeviceServerMediaSubsession::afterPlayingDummy1() {
// Unschedule any pending 'checking' task:
envir().taskScheduler().unscheduleDelayedTask(nextTask());
// Signal the event loop that we're done:
setDoneFlag();
} static void checkForAuxSDPLine(void* clientData) {
DeviceServerMediaSubsession* subsess =
(DeviceServerMediaSubsession*) clientData;
subsess->checkForAuxSDPLine1();
} void DeviceServerMediaSubsession::checkForAuxSDPLine1() {
char const* dasl; if (fAuxSDPLine != NULL) {
// Signal the event loop that we're done:
setDoneFlag();
} else if (fDummyRTPSink != NULL
&& (dasl = fDummyRTPSink->auxSDPLine()) != NULL) {
fAuxSDPLine = strDup(dasl);
fDummyRTPSink = NULL; // Signal the event loop that we're done:
setDoneFlag();
} else if (!fDoneFlag) {
// try again after a brief delay:
int uSecsToDelay = 100000; // 100 ms
nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecsToDelay,
(TaskFunc*) checkForAuxSDPLine, this);
}
}
char const* DeviceServerMediaSubsession::getAuxSDPLine(RTPSink* rtpSink,
FramedSource* inputSource) { if (fAuxSDPLine != NULL)
return fAuxSDPLine; // it's already been set up (for a previous client) if (fDummyRTPSink == NULL) { // we're not already setting it up for another, concurrent stream
// Note: For H264 video files, the 'config' information ("profile-level-id" and "sprop-parameter-sets") isn't known
// until we start reading the file. This means that "rtpSink"s "auxSDPLine()" will be NULL initially,
// and we need to start reading data from our file until this changes.
fDummyRTPSink = rtpSink; // Start reading the file:
fDummyRTPSink->startPlaying(*inputSource, afterPlayingDummy, this); // Check whether the sink's 'auxSDPLine()' is ready:
checkForAuxSDPLine(this);
} envir().taskScheduler().doEventLoop(&fDoneFlag); return fAuxSDPLine;
}
Live555 直播源 以及MediaSubsession的更多相关文章
- 基于vitamio的网络电视直播源码
这个项目是基于vitamio的网络电视直播源码,也是一个使用了vitamio的基于安卓的网络直播项目源码,可能现在网上已经有很多类似这样的视频播放应用了,不过这个还是相对来说比较完整的,希望这个案例能 ...
- 直播源格式转换教程——rtmp/rtsp/http/m3u8!!
之前寻找直播源,发现好多rtmp开头的,或者是rtsp开头的,但是ATV里面的个人链接是支持m3u8格式的.怎么办?小编发现了几个规律,网友可作参考.现在流行的直播地址差不多就这几种需要说明的是并不是 ...
- [转载]Fiddler为所欲为第四篇 直播源抓取与接口分析 [四]
今天的教程,主要是教大家如何进行“封包逆向”,关键词跳转,接口分析.(怎么样,是不是感觉和OD很像~~~)今天的教程我们以[麻花影视]为例,当然,其他APP的逻辑也是一样,通用的哦~ 首先需要做好准备 ...
- 【视频开发】【Live555】摄像头采集,264编码,live555直播
加入 摄像头采集和264编码,再使用live555直播 1.摄像头采集和264编码 将x264改成编码一帧的接口,码流不写入文件而是直接写入内存中(int Encode_frame 函数中). /* ...
- PotPlayer直播源分享
添加直播源方法: 央视CCTV1综合HD-1,rtsp://113.136.42.45:554/PLTV/88888888/224/3221226087/10000100000000060000000 ...
- 带货直播源码开发采用MySQL有什么优越性
MySQL是世界上最流行的开源关系数据库,带货直播源码使用MySQL,可实现分钟级别的数据库部署和弹性扩展,不仅经济实惠,而且稳定可靠,易于运维.云数据库 MySQL 提供备份恢复.监控.容灾.快速扩 ...
- 视频直播源码开发中的流媒体协议:rtmp协议
一.概念与摘要 视频直播源码的RTMP协议从属于应用层,被设计用来在适合的传输协议(如TCP)上复用和打包多媒体传输流(如音频.视频和互动内容).RTMP提供了一套全双工的可靠的多路复用消息服务,类似 ...
- 如何抓取直播源及视频URL地址-疯狂URL(教程)
直播源介绍 首先,我们来快速了解一下什么是直播源,所谓的直播源,其实就说推流地址,推流地址可能你也不知道是什么,那么我再简单说一下,推流地址就是,当某个直播开播的时候,需要将自己的直播状态实时的展示给 ...
- android文件管理器源码、斗鱼直播源码、企业级erp源码等
Android精选源码 文件清理管理器 自定义水平带数字的进度条以及自定义圆形带数字的进度条 利用sectionedRecyclerViewAdapter实现分组列表的recyclerView源码 流 ...
随机推荐
- JS的replace默认只替换第一个匹配项
1. JS的replace默认只替换第一个匹配项. 解决方法: 使用正则表达式进行匹配替换[ ①.replace(new RegExp(②,"g") ,③); ] ①:包含 ...
- ng-book札记——内置指令
Angular提供了一些内置指令(directive),这些添加在HTML元素(element)上的特性(attribute)可以赋予更多的动态行为. NgIf ngIf指令用于在某个条件下显示或者隐 ...
- PHP 5 Array 函数
PHP Array 简介 PHP Array 函数允许您访问并操作数组. 支持简单的数组和多维数组. 安装 PHP Array 函数是 PHP 核心的组成部分.无需安装即可使用这些函数. PHP 5 ...
- Arrays的二分查找
二分查找也称为折半查找,是对有序元素查找的一种算法,在查找的过程中,不断的将搜索长度减半,因此效率不错.Java的JDK提供了二分法查找的算法,使用的方法是Arrays.binarySearch(). ...
- Java内存泄漏分析系列之七:使用MAT的Histogram和Dominator Tree定位溢出源
原文地址:http://www.javatang.com 基础概念 先列出几个基础的概念: Shallow Heap 和 Retained Heap Shallow Heap表示对象本身占用内存的大小 ...
- Cassandra Secondary Index 介绍
摘要 本文主要介绍cassandra中的索引,物化视图,有些知识点需要对cassandra有基本的认识才能理解.比如数据在cassandra节点中如何分布.如果有不明白的地方可以看本专栏之前文章.或者 ...
- Objective-C's Init Method
初始化器在其他面向对象的语言中(比如Java)指的是构造器. Objective-C同样拥有对象构造器在init形式的方法中.不管如何,在Objc中这些方法没有什么特殊的行为. 按照惯例,程序猿在in ...
- Android图表库MPAndroidChart(四)——条形图的绘制过程过程,隐隐约约我看到了套路
Android图表库MPAndroidChart(四)--条形图的绘制过程过程,隐隐约约我看到了套路 在学习本课程之前我建议先把我之前的博客看完,这样对整体的流程有一个大致的了解 Android图表库 ...
- Excel init
Sub Test() Dim r As Range Dim a As Integer a = For Each r In Range("b1:b6") If r.Font.Bold ...
- Dynamics CRM FORM脚本库加载本地脚本
用传统的开发方式,js脚本都是保存在数据库中的,这样也方便迁移,但如果不想存数据库而是存在物理磁盘上,则可通过下述代码,将脚本存放在CRMWEB文件夹的某个路径下,每次都动态引用本地JS. funct ...