首页 > 代码库 > Live555 直播源 以及MediaSubsession

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;
}