/* * 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,布布扣,bubuko.com
原文地址:http://blog.csdn.net/zblue78/article/details/38303997