From 1abced42eb3997ef9ef675bfe990f7913ea73f2f Mon Sep 17 00:00:00 2001
From: houxiao <houxiao@454eff88-639b-444f-9e54-f578c98de674>
Date: 星期五, 23 十二月 2016 18:34:10 +0800
Subject: [PATCH] add h264 encoder and rtsp server

---
 RtspFace/make.sh                              |   13 
 RtspFace/PL_RTSPServer.cpp                    |  194 +++++++++++-
 /dev/null                                     |  455 ------------------------------
 RtspFace/PL_H264Decoder.cpp                   |    8 
 RtspFace/main.cpp                             |    9 
 RtspFace/PL_H264Encoder.cpp                   |  196 +++++++++++-
 RtspFace/live555/testProgs/testRTSPClient.hpp |    4 
 RtspFace/PL_RTSPClient.cpp                    |    4 
 8 files changed, 369 insertions(+), 514 deletions(-)

diff --git a/RtspFace/PL_H264Decoder.cpp b/RtspFace/PL_H264Decoder.cpp
index 9f51b43..879fa6f 100644
--- a/RtspFace/PL_H264Decoder.cpp
+++ b/RtspFace/PL_H264Decoder.cpp
@@ -126,7 +126,7 @@
 	in->pAVCodecContext->codec_type = AVMEDIA_TYPE_VIDEO;
 	in->pAVCodecContext->bit_rate = 0;
 	in->pAVCodecContext->time_base.den = 25;
-	in->pAVCodecContext->width = 1920;
+	in->pAVCodecContext->width = 1920;//#todo get from pm
 	in->pAVCodecContext->height = 1080;
 
 	if (in->pAVCodecContext->extradata == NULL)  
@@ -159,7 +159,7 @@
 bool decodeH264(H264Decoder_Internal* in, uint8_t* buffer, size_t buffSize)  
 {
 	AVPacket packet = {0};
-	int frameFinished = buffSize;
+	int gotPicture = buffSize; // frameFinished
 
 	if (av_packet_from_data(&packet, buffer, buffSize) != 0)
 	{  
@@ -168,8 +168,8 @@
 	}  
 	
 	// decode
-	avcodec_decode_video2(in->pAVCodecContext, in->pAVFrame, &frameFinished, &packet);
-	if(frameFinished)
+	avcodec_decode_video2(in->pAVCodecContext, in->pAVFrame, &gotPicture, &packet);
+	if(gotPicture)
 	{
 		// decode ok
 		return true;
diff --git a/RtspFace/PL_H264Encoder.cpp b/RtspFace/PL_H264Encoder.cpp
index ebdfb7f..9fc0a0b 100644
--- a/RtspFace/PL_H264Encoder.cpp
+++ b/RtspFace/PL_H264Encoder.cpp
@@ -2,24 +2,33 @@
 
 extern "C"
 {
-	#include <libyuv.h>
+	#include <libavcodec/avcodec.h>
+	#include <libavutil/frame.h>
+	#include <libavformat/avformat.h>
+	#include "libavutil/imgutils.h"
 }
 
-struct PL_H264Encoder_Internal
+struct H264Encoder_Internal
 {
-	uint8_t buffer[1920*1080*4];
+	uint8_t buffer[1920*1080*3];
 	size_t buffSize;
 	size_t buffSizeMax;
-
 	bool payError;
+	bool ffmpegInited;
+	size_t frameCount;
+
+	AVCodecContext* pAVCodecContext;
+	AVFrame* pAVFrame;//#todo delete
 	
-	PL_H264Encoder_Internal() : 
+	H264Encoder_Internal() : 
 		buffSize(0), buffSizeMax(sizeof(buffer)), 
-		payError(true)
+		payError(true), ffmpegInited(false), frameCount(0), 
+		pAVCodecContext(nullptr), pAVFrame(nullptr)
+		
 	{
 	}
 	
-	~PL_H264Encoder_Internal()
+	~H264Encoder_Internal()
 	{
 	}
 	
@@ -27,6 +36,11 @@
 	{
 		buffSize = 0;
 		payError = true;
+		ffmpegInited = false;
+		frameCount = 0;
+		
+		pAVCodecContext = nullptr;
+		pAVFrame = nullptr;
 	}
 };
 
@@ -35,52 +49,180 @@
 	return new PL_H264Encoder;
 }
 
-PL_H264Encoder::PL_H264Encoder() : internal(new PL_H264Encoder_Internal)
+PL_H264Encoder::PL_H264Encoder() : internal(new H264Encoder_Internal)
 {
 }
 
 PL_H264Encoder::~PL_H264Encoder()
 {
-	delete (PL_H264Encoder_Internal*)internal;
+	delete (H264Encoder_Internal*)internal;
 	internal= nullptr;
 }
 
 bool PL_H264Encoder::init(void* args)
 {
-	PL_H264Encoder_Internal* in = (PL_H264Encoder_Internal*)internal;
+	H264Encoder_Internal* in = (H264Encoder_Internal*)internal;
 	in->reset();
-
+	
 	return true;
 }
 
 void PL_H264Encoder::finit()
 {
-	PL_H264Encoder_Internal* in = (PL_H264Encoder_Internal*)internal;
+	H264Encoder_Internal* in = (H264Encoder_Internal*)internal;
 	
+}
+
+bool initH264EncoderEnv(H264Encoder_Internal* in)
+{
+	av_register_all();
+
+	// find the video encoder
+	AVCodec* avCodec = avcodec_find_encoder(AV_CODEC_ID_H264);
+
+	if (!avCodec)   
+	{  
+		printf("codec not found!\n");  
+		return false;  
+	}  
+
+	in->pAVCodecContext = avcodec_alloc_context3(avCodec);
+
+	in->pAVCodecContext->bit_rate = 3*1024*1024*8; // 3MB
+    in->pAVCodecContext->width = 1920;
+    in->pAVCodecContext->height = 1080;//#todo from config
+    in->pAVCodecContext->time_base.num=1;
+    in->pAVCodecContext->time_base.den=25;
+    in->pAVCodecContext->gop_size = 20;
+    in->pAVCodecContext->max_b_frames = 0;
+    in->pAVCodecContext->pix_fmt = AV_PIX_FMT_YUV420P;
+
+	if(avcodec_open2(in->pAVCodecContext, avCodec, NULL) >= 0)
+	{
+		in->pAVFrame = av_frame_alloc(); // Allocate video frame
+		
+		in->pAVFrame->format = in->pAVCodecContext->pix_fmt;  
+		in->pAVFrame->width  = in->pAVCodecContext->width;  
+		in->pAVFrame->height = in->pAVCodecContext->height;
+		
+		int ret = av_image_alloc(in->pAVFrame->data, in->pAVFrame->linesize, in->pAVCodecContext->width, in->pAVCodecContext->height, 
+							in->pAVCodecContext->pix_fmt, 16);  
+		if (ret < 0)
+		{  
+			printf("av_image_alloc error\n");
+			return false;
+		} 
+	}
+	else
+	{
+		printf("avcodec_open2 error\n");
+		return false;
+	}
+	
+	return true;
+}
+
+void copyAVFrame(AVFrame* dest, AVFrame* src)
+{
+	int height = dest->height;
+	int width = dest->width;
+	
+	memcpy(dest->data[0], src->data[0], height * width); // Y
+	memcpy(dest->data[1], src->data[1], height * width / 4); // U
+	memcpy(dest->data[2], src->data[2], height * width / 4); // V
+}
+
+bool encodeH264(H264Encoder_Internal* in, AVFrame* pAVFrame, size_t buffSize)  
+{
+	in->buffSize = 0;
+	in->frameCount++;
+
+	copyAVFrame(in->pAVFrame, pAVFrame);
+	in->pAVFrame->pts = in->frameCount;
+	
+	AVPacket pAVPacket = {0};
+	av_init_packet(&pAVPacket);
+	
+	// encode the image
+	int gotPacket = 0;
+	int ret = avcodec_encode_video2(in->pAVCodecContext, &pAVPacket, in->pAVFrame, &gotPacket);  
+	if (ret < 0)
+	{
+		printf("avcodec_encode_video2 (1) error=%d\n", ret);
+		return false;
+	}
+	
+	if (gotPacket > 0)
+	{
+		printf("Succeed to encode (1) frame=%d, size=%d\n", in->pAVFrame->pts, pAVPacket.size);
+		memcpy(in->buffer + in->buffSize, pAVPacket.data, pAVPacket.size);
+		in->buffSize += pAVPacket.size;
+		av_free_packet(&pAVPacket);
+	}
+	
+	//#todo finit
+	//Flush Encoder  
+	//while (gotPacket > 0)
+	//{  
+	//	ret = avcodec_encode_video2(in->pAVCodecContext, &pAVPacket, NULL, &gotPacket);
+	//	if (ret < 0)
+	//	{
+	//		printf("avcodec_encode_video2 (2) error=%d\n", ret);
+	//		return false;
+	//	}  
+	//	if (gotPacket > 0)
+	//	{  
+	//		printf("Succeed to encode (2) frame=%d, size=%d\n", in->pAVFrame->pts, pAVPacket.size);
+	//		memcpy(in->buffer + in->buffSize, pAVPacket.data, pAVPacket.size);
+	//		in->buffSize += pAVPacket.size; 
+	//		av_free_packet(&pAVPacket);  
+	//	}  
+	//} 
+	
+	//#test
+	if (in->buffSize > 0)
+	{
+		static FILE * pFile = fopen("out.h264","wba+");
+		fwrite (in->buffer , sizeof(char), in->buffSize, pFile);
+		fflush(pFile);
+	}
+	
+	in->payError = (in->buffSize == 0);
+	return !(in->payError);
 }
 
 bool PL_H264Encoder::pay(const PipeMaterial& pm)
 {
-	PL_H264Encoder_Internal* in = (PL_H264Encoder_Internal*)internal;
+	H264Encoder_Internal* in = (H264Encoder_Internal*)internal;
 	
-	//in->buffer readly
-
-	//static size_t f=0;
-	//char fname[50];
-	//sprintf(fname, "%u.bgra", ++f);
-	//FILE * pFile = fopen (fname,"wb");
-	//fwrite (in->buffer , sizeof(char), in->buffSize, pFile);
-	//fclose(pFile);
-
-	return true;
+	in->payError = true;
+	
+	if (!in->ffmpegInited)
+	{
+		bool ret = initH264EncoderEnv(in);
+		if (!ret)
+		{
+			printf("initH264EncoderEnv error");
+			return false;
+		}
+		else
+			in->ffmpegInited = true;
+	}
+	
+	bool ret = encodeH264(in, (AVFrame*)pm.buffer, pm.buffSize);
+	in->payError = !ret;
+	return ret;
 }
 
 bool PL_H264Encoder::gain(PipeMaterial& pm)
 {
-	PL_H264Encoder_Internal* in = (PL_H264Encoder_Internal*)internal;
+	H264Encoder_Internal* in = (H264Encoder_Internal*)internal;
 
-	pm.buffer = in->buffer;
-	pm.buffSize = in->buffSize;
+	if (!in->payError)
+	{
+		pm.buffer = in->buffer;
+		pm.buffSize = in->buffSize;
+	}
 	pm.former = this;
-	return true;
+	return !in->payError;
 }
diff --git a/RtspFace/PL_RTSPClient.cpp b/RtspFace/PL_RTSPClient.cpp
index b83ec88..b26b2c1 100644
--- a/RtspFace/PL_RTSPClient.cpp
+++ b/RtspFace/PL_RTSPClient.cpp
@@ -36,12 +36,14 @@
 		{
 			pthread_mutex_destroy(frame_mutex);
 			delete frame_mutex;
+			frame_mutex = nullptr;
 		}
 		
 		if (continue_mutex != nullptr)
 		{
 			pthread_mutex_destroy(continue_mutex);
 			delete continue_mutex;
+			continue_mutex = nullptr;
 		}
 	}
 	
@@ -58,6 +60,7 @@
 		{
 			pthread_mutex_destroy(frame_mutex);
 			delete frame_mutex;
+			frame_mutex = nullptr;
 		}
 		
 		frame_mutex = new pthread_mutex_t;
@@ -67,6 +70,7 @@
 		{
 			pthread_mutex_destroy(continue_mutex);
 			delete continue_mutex;
+			continue_mutex = nullptr;
 		}
 		
 		continue_mutex = new pthread_mutex_t;
diff --git a/RtspFace/PL_RTSPServer.cpp b/RtspFace/PL_RTSPServer.cpp
index ad27c00..936b31d 100644
--- a/RtspFace/PL_RTSPServer.cpp
+++ b/RtspFace/PL_RTSPServer.cpp
@@ -1,29 +1,123 @@
 #include "PL_RTSPServer.h"
 
-#include "testOnDemandRTSPServer.hpp"
+#include <liveMedia.hh>
+#include <BasicUsageEnvironment.hh>
+
+class MyH264FramedSource : public FramedSource
+{
+public:
+	static MyH264FramedSource* createNew(UsageEnvironment& env);
+
+protected:
+	MyH264FramedSource(UsageEnvironment& env)
+	virtual ~MyH264FramedSource()
+
+	// overide FramedSource
+	virtual void doGetNextFrame()
+	{
+		// deliverFrame
+		//if (fFrameSize > 0)
+		//{
+		//	// send Frame to the consumer
+		//	FramedSource::afterGetting(this);			
+		//}
+		
+		
+		// isCurrentlyAwaitingData
+			//if (frame->m_size > fMaxSize) 
+			//{
+			//	fFrameSize = fMaxSize;
+			//	fNumTruncatedBytes = frame->m_size - fMaxSize;
+			//} 
+			//else 
+			//{
+			//	fFrameSize = frame->m_size;
+			//}
+		//memcpy(fTo, frame->m_buffer, fFrameSize);
+		//if (fFrameSize > 0)
+		//	FramedSource::afterGetting(this);
+	}
+	
+	virtual void doStopGettingFrames()
+	{
+		FramedSource::doStopGettingFrames();
+	}
+};
 
 struct PL_RTSPServer_Internal
 {
-	uint8_t buffer[1920*1080*4];
-	size_t buffSize;
-	size_t buffSizeMax;
+	//uint8_t buffer[1920*1080*4];
+	//size_t buffSize;
+	//size_t buffSizeMax;
 
 	bool payError;
+	pthread_t live_daemon_thid;
+	pthread_mutex_t* frame_mutex;
+	bool live_daemon_running;
+	
+	UsageEnvironment* env;
+
+	// To make the second and subsequent client for each stream reuse the same
+	// input stream as the first client (rather than playing the file from the
+	// start for each client), change the following "False" to "True":
+	Boolean reuseFirstSource;
+
+	// To stream *only* MPEG-1 or 2 video "I" frames
+	// (e.g., to reduce network bandwidth),
+	// change the following "False" to "True":
+	Boolean iFramesOnly;
+	
+	UserAuthenticationDatabase* authDB;
+
+	RTSPServer* rtspServer;//#todo delete
+	
+	char descriptionString[1024];
 	
 	PL_RTSPServer_Internal() : 
-		buffSize(0), buffSizeMax(sizeof(buffer)), 
-		payError(true)
+		//buffSize(0), buffSizeMax(sizeof(buffer)), 
+		payError(true), live_daemon_thid(0), frame_mutex(nullptr), live_daemon_running(false), 
+		env(nullptr), reuseFirstSource(False), iFramesOnly(False), authDB(nullptr), 
+		rtspServer(nullptr);
 	{
+		pthread_mutex_init(frame_mutex, NULL);
 	}
 	
 	~PL_RTSPServer_Internal()
 	{
+		if (frame_mutex != nullptr)
+		{
+			pthread_mutex_destroy(frame_mutex);
+			delete frame_mutex;
+			frame_mutex = nullptr;
+		}
 	}
 	
 	void reset()
 	{
-		buffSize = 0;
+		//buffSize = 0;
+
 		payError = true;
+
+		if (frame_mutex != nullptr)
+		{
+			pthread_mutex_destroy(frame_mutex);
+			delete frame_mutex;
+			frame_mutex = nullptr;
+		}
+		
+		frame_mutex = new pthread_mutex_t;
+		pthread_mutex_init(frame_mutex, NULL);
+
+		live_daemon_thid = 0;
+		live_daemon_running = false;
+		
+		env = nullptr;
+		reuseFirstSource = False;
+		iFramesOnly = False;
+		authDB = nullptr; 
+		rtspServer = nullptr;
+		
+		strcpy(descriptionString, "Session streamed by \"testOnDemandRTSPServer\"");
 	}
 };
 
@@ -42,32 +136,92 @@
 	internal= nullptr;
 }
 
+void* live_daemon_thd(void* arg)
+{
+	RTSPClient_Internal* in = (RTSPClient_Internal*)arg;
+	
+	// Begin by setting up our usage environment:
+	TaskScheduler* scheduler = BasicTaskScheduler::createNew();
+	in->env = BasicUsageEnvironment::createNew(*scheduler);
+
+#ifdef ACCESS_CONTROL
+	// To implement client access control to the RTSP server, do the following:
+	in->authDB = new UserAuthenticationDatabase;
+	in->authDB->addUserRecord("username1", "password1"); // replace these with real strings
+	// Repeat the above with each <username>, <password> that you wish to allow
+	// access to the server.
+#endif
+
+	// Create the RTSP server:
+	in->rtspServer = RTSPServer::createNew(*env, 8554, authDB);
+	if (rtspServer == NULL)
+	{
+		*(in->env) << "Failed to create RTSP server: " << env->getResultMsg() << "\n";
+		return;
+	}
+
+	// Set up each of the possible streams that can be served by the
+	// RTSP server.  Each such stream is implemented using a
+	// "ServerMediaSession" object, plus one or more
+	// "ServerMediaSubsession" objects for each audio/video substream.
+	
+    char const* streamName = "plH264Encoder";
+    ServerMediaSession* sms = ServerMediaSession::createNew(*(in->env), streamName, streamName, in->descriptionString);
+    sms->addSubsession(MyH264FramedSource::createNew(*(in->env), in));
+    in->rtspServer->addServerMediaSession(sms);
+	
+	// announceStream
+	char* url = rtspServer->rtspURL(sms);
+	*(in->env) << "\n\"" << streamName << "\" stream, from the file \"" << inputFileName << "\"\n";
+	*(in->env) << "Play this stream using the URL \"" << url << "\"\n";
+	delete[] url;
+	
+	// Also, attempt to create a HTTP server for RTSP-over-HTTP tunneling.
+	// Try first with the default HTTP port (80), and then with the alternative HTTP
+	// port numbers (8000 and 8080).
+
+	if (rtspServer->setUpTunnelingOverHTTP(80))
+		*(in->env) << "\n(We use port " << rtspServer->httpServerPortNum() << " for optional RTSP-over-HTTP tunneling.)\n";
+	else
+		*(in->env) << "\n(RTSP-over-HTTP tunneling is not available.)\n";
+
+	in->live_daemon_running = true;
+	env->taskScheduler().doEventLoop(); // does not return
+	in->live_daemon_running = false;
+}
+
 bool PL_RTSPServer::init(void* args)
 {
 	PL_RTSPServer_Internal* in = (PL_RTSPServer_Internal*)internal;
 	in->reset();
+	
+	int ret = pthread_mutex_lock(in->frame_mutex);
+	if(ret != 0)
+	{
+		printf("pthread_mutex_lock frame_mutex: %s/n", strerror(ret));
+		return false;
+	}
+	
+	ret = pthread_create(&(in->live_daemon_thid), NULL, live_daemon_thd, in);
+	if(ret != 0)
+	{
+		printf("pthread_create: %s/n", strerror(ret));
+		return false;
+	}
 
 	return true;
 }
 
 void PL_RTSPServer::finit()
 {
-	PL_RTSPServer_Internal* in = (PL_RTSPServer_Internal*)internal;
-	
+	RTSPClient_Internal* in = (RTSPClient_Internal*)internal;
+
+	pthread_join(in->live_daemon_thid, NULL);
 }
 
 bool PL_RTSPServer::pay(const PipeMaterial& pm)
 {
 	PL_RTSPServer_Internal* in = (PL_RTSPServer_Internal*)internal;
-	
-	//in->buffer readly
-
-	//static size_t f=0;
-	//char fname[50];
-	//sprintf(fname, "%u.bgra", ++f);
-	//FILE * pFile = fopen (fname,"wb");
-	//fwrite (in->buffer , sizeof(char), in->buffSize, pFile);
-	//fclose(pFile);
 
 	return true;
 }
@@ -76,8 +230,8 @@
 {
 	PL_RTSPServer_Internal* in = (PL_RTSPServer_Internal*)internal;
 
-	pm.buffer = in->buffer;
-	pm.buffSize = in->buffSize;
+	pm.buffer = nullptr;
+	pm.buffSize = 0;
 	pm.former = this;
 	return true;
 }
diff --git a/RtspFace/live555/testProgs/testH264VideoStreamer.hpp b/RtspFace/live555/testProgs/testH264VideoStreamer.hpp
deleted file mode 100644
index 74fe461..0000000
--- a/RtspFace/live555/testProgs/testH264VideoStreamer.hpp
+++ /dev/null
@@ -1,132 +0,0 @@
-/**********
-This library is free software; you can redistribute it and/or modify it under
-the terms of the GNU Lesser General Public License as published by the
-Free Software Foundation; either version 3 of the License, or (at your
-option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
-
-This library is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
-more details.
-
-You should have received a copy of the GNU Lesser General Public License
-along with this library; if not, write to the Free Software Foundation, Inc.,
-51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-**********/
-// Copyright (c) 1996-2017, Live Networks, Inc.  All rights reserved
-// A test program that reads a H.264 Elementary Stream video file
-// and streams it using RTP
-// main program
-//
-// NOTE: For this application to work, the H.264 Elementary Stream video file *must* contain SPS and PPS NAL units,
-// ideally at or near the start of the file.  These SPS and PPS NAL units are used to specify 'configuration' information
-// that is set in the output stream's SDP description (by the RTSP server that is built in to this application).
-// Note also that - unlike some other "*Streamer" demo applications - the resulting stream can be received only using a
-// RTSP client (such as "openRTSP")
-
-#include <liveMedia.hh>
-#include <BasicUsageEnvironment.hh>
-#include <GroupsockHelper.hh>
-
-UsageEnvironment* env;
-char const* inputFileName = "test.264";
-H264VideoStreamFramer* videoSource;
-RTPSink* videoSink;
-
-void play(); // forward
-
-int main(int argc, char** argv) {
-  // Begin by setting up our usage environment:
-  TaskScheduler* scheduler = BasicTaskScheduler::createNew();
-  env = BasicUsageEnvironment::createNew(*scheduler);
-
-  // Create 'groupsocks' for RTP and RTCP:
-  struct in_addr destinationAddress;
-  destinationAddress.s_addr = chooseRandomIPv4SSMAddress(*env);
-  // Note: This is a multicast address.  If you wish instead to stream
-  // using unicast, then you should use the "testOnDemandRTSPServer"
-  // test program - not this test program - as a model.
-
-  const unsigned short rtpPortNum = 18888;
-  const unsigned short rtcpPortNum = rtpPortNum+1;
-  const unsigned char ttl = 255;
-
-  const Port rtpPort(rtpPortNum);
-  const Port rtcpPort(rtcpPortNum);
-
-  Groupsock rtpGroupsock(*env, destinationAddress, rtpPort, ttl);
-  rtpGroupsock.multicastSendOnly(); // we're a SSM source
-  Groupsock rtcpGroupsock(*env, destinationAddress, rtcpPort, ttl);
-  rtcpGroupsock.multicastSendOnly(); // we're a SSM source
-
-  // Create a 'H264 Video RTP' sink from the RTP 'groupsock':
-  OutPacketBuffer::maxSize = 100000;
-  videoSink = H264VideoRTPSink::createNew(*env, &rtpGroupsock, 96);
-
-  // Create (and start) a 'RTCP instance' for this RTP sink:
-  const unsigned estimatedSessionBandwidth = 500; // in kbps; for RTCP b/w share
-  const unsigned maxCNAMElen = 100;
-  unsigned char CNAME[maxCNAMElen+1];
-  gethostname((char*)CNAME, maxCNAMElen);
-  CNAME[maxCNAMElen] = '\0'; // just in case
-  RTCPInstance* rtcp
-  = RTCPInstance::createNew(*env, &rtcpGroupsock,
-			    estimatedSessionBandwidth, CNAME,
-			    videoSink, NULL /* we're a server */,
-			    True /* we're a SSM source */);
-  // Note: This starts RTCP running automatically
-
-  RTSPServer* rtspServer = RTSPServer::createNew(*env, 8554);
-  if (rtspServer == NULL) {
-    *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";
-    exit(1);
-  }
-  ServerMediaSession* sms
-    = ServerMediaSession::createNew(*env, "testStream", inputFileName,
-		   "Session streamed by \"testH264VideoStreamer\"",
-					   True /*SSM*/);
-  sms->addSubsession(PassiveServerMediaSubsession::createNew(*videoSink, rtcp));
-  rtspServer->addServerMediaSession(sms);
-
-  char* url = rtspServer->rtspURL(sms);
-  *env << "Play this stream using the URL \"" << url << "\"\n";
-  delete[] url;
-
-  // Start the streaming:
-  *env << "Beginning streaming...\n";
-  play();
-
-  env->taskScheduler().doEventLoop(); // does not return
-
-  return 0; // only to prevent compiler warning
-}
-
-void afterPlaying(void* /*clientData*/) {
-  *env << "...done reading from file\n";
-  videoSink->stopPlaying();
-  Medium::close(videoSource);
-  // Note that this also closes the input file that this source read from.
-
-  // Start playing once again:
-  play();
-}
-
-void play() {
-  // Open the input file as a 'byte-stream file source':
-  ByteStreamFileSource* fileSource
-    = ByteStreamFileSource::createNew(*env, inputFileName);
-  if (fileSource == NULL) {
-    *env << "Unable to open file \"" << inputFileName
-         << "\" as a byte-stream file source\n";
-    exit(1);
-  }
-
-  FramedSource* videoES = fileSource;
-
-  // Create a framer for the Video Elementary Stream:
-  videoSource = H264VideoStreamFramer::createNew(*env, videoES);
-
-  // Finally, start playing:
-  *env << "Beginning to read from file...\n";
-  videoSink->startPlaying(*videoSource, afterPlaying, videoSink);
-}
diff --git a/RtspFace/live555/testProgs/testOnDemandRTSPServer.hpp b/RtspFace/live555/testProgs/testOnDemandRTSPServer.hpp
deleted file mode 100644
index 2608308..0000000
--- a/RtspFace/live555/testProgs/testOnDemandRTSPServer.hpp
+++ /dev/null
@@ -1,455 +0,0 @@
-/**********
-This library is free software; you can redistribute it and/or modify it under
-the terms of the GNU Lesser General Public License as published by the
-Free Software Foundation; either version 3 of the License, or (at your
-option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
-
-This library is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
-more details.
-
-You should have received a copy of the GNU Lesser General Public License
-along with this library; if not, write to the Free Software Foundation, Inc.,
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
-**********/
-// Copyright (c) 1996-2017, Live Networks, Inc.  All rights reserved
-// A test program that demonstrates how to stream - via unicast RTP
-// - various kinds of file on demand, using a built-in RTSP server.
-// main program
-
-#include "liveMedia.hh"
-#include "BasicUsageEnvironment.hh"
-
-UsageEnvironment* env;
-
-// To make the second and subsequent client for each stream reuse the same
-// input stream as the first client (rather than playing the file from the
-// start for each client), change the following "False" to "True":
-Boolean reuseFirstSource = False;
-
-// To stream *only* MPEG-1 or 2 video "I" frames
-// (e.g., to reduce network bandwidth),
-// change the following "False" to "True":
-Boolean iFramesOnly = False;
-
-static void announceStream(RTSPServer* rtspServer, ServerMediaSession* sms,
-			   char const* streamName, char const* inputFileName); // fwd
-
-static char newDemuxWatchVariable;
-
-static MatroskaFileServerDemux* matroskaDemux;
-static void onMatroskaDemuxCreation(MatroskaFileServerDemux* newDemux, void* /*clientData*/) {
-  matroskaDemux = newDemux;
-  newDemuxWatchVariable = 1;
-}
-
-static OggFileServerDemux* oggDemux;
-static void onOggDemuxCreation(OggFileServerDemux* newDemux, void* /*clientData*/) {
-  oggDemux = newDemux;
-  newDemuxWatchVariable = 1;
-}
-
-int main(int argc, char** argv) {
-  // Begin by setting up our usage environment:
-  TaskScheduler* scheduler = BasicTaskScheduler::createNew();
-  env = BasicUsageEnvironment::createNew(*scheduler);
-
-  UserAuthenticationDatabase* authDB = NULL;
-#ifdef ACCESS_CONTROL
-  // To implement client access control to the RTSP server, do the following:
-  authDB = new UserAuthenticationDatabase;
-  authDB->addUserRecord("username1", "password1"); // replace these with real strings
-  // Repeat the above with each <username>, <password> that you wish to allow
-  // access to the server.
-#endif
-
-  // Create the RTSP server:
-  RTSPServer* rtspServer = RTSPServer::createNew(*env, 8554, authDB);
-  if (rtspServer == NULL) {
-    *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";
-    exit(1);
-  }
-
-  char const* descriptionString
-    = "Session streamed by \"testOnDemandRTSPServer\"";
-
-  // Set up each of the possible streams that can be served by the
-  // RTSP server.  Each such stream is implemented using a
-  // "ServerMediaSession" object, plus one or more
-  // "ServerMediaSubsession" objects for each audio/video substream.
-
-  // A MPEG-4 video elementary stream:
-  {
-    char const* streamName = "mpeg4ESVideoTest";
-    char const* inputFileName = "test.m4e";
-    ServerMediaSession* sms
-      = ServerMediaSession::createNew(*env, streamName, streamName,
-				      descriptionString);
-    sms->addSubsession(MPEG4VideoFileServerMediaSubsession
-		       ::createNew(*env, inputFileName, reuseFirstSource));
-    rtspServer->addServerMediaSession(sms);
-
-    announceStream(rtspServer, sms, streamName, inputFileName);
-  }
-
-  // A H.264 video elementary stream:
-  {
-    char const* streamName = "h264ESVideoTest";
-    char const* inputFileName = "test.264";
-    ServerMediaSession* sms
-      = ServerMediaSession::createNew(*env, streamName, streamName,
-				      descriptionString);
-    sms->addSubsession(H264VideoFileServerMediaSubsession
-		       ::createNew(*env, inputFileName, reuseFirstSource));
-    rtspServer->addServerMediaSession(sms);
-
-    announceStream(rtspServer, sms, streamName, inputFileName);
-  }
-
-  // A H.265 video elementary stream:
-  {
-    char const* streamName = "h265ESVideoTest";
-    char const* inputFileName = "test.265";
-    ServerMediaSession* sms
-      = ServerMediaSession::createNew(*env, streamName, streamName,
-				      descriptionString);
-    sms->addSubsession(H265VideoFileServerMediaSubsession
-		       ::createNew(*env, inputFileName, reuseFirstSource));
-    rtspServer->addServerMediaSession(sms);
-
-    announceStream(rtspServer, sms, streamName, inputFileName);
-  }
-
-  // A MPEG-1 or 2 audio+video program stream:
-  {
-    char const* streamName = "mpeg1or2AudioVideoTest";
-    char const* inputFileName = "test.mpg";
-    // NOTE: This *must* be a Program Stream; not an Elementary Stream
-    ServerMediaSession* sms
-      = ServerMediaSession::createNew(*env, streamName, streamName,
-				      descriptionString);
-    MPEG1or2FileServerDemux* demux
-      = MPEG1or2FileServerDemux::createNew(*env, inputFileName, reuseFirstSource);
-    sms->addSubsession(demux->newVideoServerMediaSubsession(iFramesOnly));
-    sms->addSubsession(demux->newAudioServerMediaSubsession());
-    rtspServer->addServerMediaSession(sms);
-
-    announceStream(rtspServer, sms, streamName, inputFileName);
-  }
-
-  // A MPEG-1 or 2 video elementary stream:
-  {
-    char const* streamName = "mpeg1or2ESVideoTest";
-    char const* inputFileName = "testv.mpg";
-    // NOTE: This *must* be a Video Elementary Stream; not a Program Stream
-    ServerMediaSession* sms
-      = ServerMediaSession::createNew(*env, streamName, streamName,
-				      descriptionString);
-    sms->addSubsession(MPEG1or2VideoFileServerMediaSubsession
-	       ::createNew(*env, inputFileName, reuseFirstSource, iFramesOnly));
-    rtspServer->addServerMediaSession(sms);
-
-    announceStream(rtspServer, sms, streamName, inputFileName);
-  }
-
-  // A MP3 audio stream (actually, any MPEG-1 or 2 audio file will work):
-  // To stream using 'ADUs' rather than raw MP3 frames, uncomment the following:
-//#define STREAM_USING_ADUS 1
-  // To also reorder ADUs before streaming, uncomment the following:
-//#define INTERLEAVE_ADUS 1
-  // (For more information about ADUs and interleaving,
-  //  see <http://www.live555.com/rtp-mp3/>)
-  {
-    char const* streamName = "mp3AudioTest";
-    char const* inputFileName = "test.mp3";
-    ServerMediaSession* sms
-      = ServerMediaSession::createNew(*env, streamName, streamName,
-				      descriptionString);
-    Boolean useADUs = False;
-    Interleaving* interleaving = NULL;
-#ifdef STREAM_USING_ADUS
-    useADUs = True;
-#ifdef INTERLEAVE_ADUS
-    unsigned char interleaveCycle[] = {0,2,1,3}; // or choose your own...
-    unsigned const interleaveCycleSize
-      = (sizeof interleaveCycle)/(sizeof (unsigned char));
-    interleaving = new Interleaving(interleaveCycleSize, interleaveCycle);
-#endif
-#endif
-    sms->addSubsession(MP3AudioFileServerMediaSubsession
-		       ::createNew(*env, inputFileName, reuseFirstSource,
-				   useADUs, interleaving));
-    rtspServer->addServerMediaSession(sms);
-
-    announceStream(rtspServer, sms, streamName, inputFileName);
-  }
-
-  // A WAV audio stream:
-  {
-    char const* streamName = "wavAudioTest";
-    char const* inputFileName = "test.wav";
-    ServerMediaSession* sms
-      = ServerMediaSession::createNew(*env, streamName, streamName,
-				      descriptionString);
-    // To convert 16-bit PCM data to 8-bit u-law, prior to streaming,
-    // change the following to True:
-    Boolean convertToULaw = False;
-    sms->addSubsession(WAVAudioFileServerMediaSubsession
-	       ::createNew(*env, inputFileName, reuseFirstSource, convertToULaw));
-    rtspServer->addServerMediaSession(sms);
-
-    announceStream(rtspServer, sms, streamName, inputFileName);
-  }
-
-  // An AMR audio stream:
-  {
-    char const* streamName = "amrAudioTest";
-    char const* inputFileName = "test.amr";
-    ServerMediaSession* sms
-      = ServerMediaSession::createNew(*env, streamName, streamName,
-				      descriptionString);
-    sms->addSubsession(AMRAudioFileServerMediaSubsession
-		       ::createNew(*env, inputFileName, reuseFirstSource));
-    rtspServer->addServerMediaSession(sms);
-
-    announceStream(rtspServer, sms, streamName, inputFileName);
-  }
-
-  // A 'VOB' file (e.g., from an unencrypted DVD):
-  {
-    char const* streamName = "vobTest";
-    char const* inputFileName = "test.vob";
-    ServerMediaSession* sms
-      = ServerMediaSession::createNew(*env, streamName, streamName,
-				      descriptionString);
-    // Note: VOB files are MPEG-2 Program Stream files, but using AC-3 audio
-    MPEG1or2FileServerDemux* demux
-      = MPEG1or2FileServerDemux::createNew(*env, inputFileName, reuseFirstSource);
-    sms->addSubsession(demux->newVideoServerMediaSubsession(iFramesOnly));
-    sms->addSubsession(demux->newAC3AudioServerMediaSubsession());
-    rtspServer->addServerMediaSession(sms);
-
-    announceStream(rtspServer, sms, streamName, inputFileName);
-  }
-
-  // A MPEG-2 Transport Stream:
-  {
-    char const* streamName = "mpeg2TransportStreamTest";
-    char const* inputFileName = "test.ts";
-    char const* indexFileName = "test.tsx";
-    ServerMediaSession* sms
-      = ServerMediaSession::createNew(*env, streamName, streamName,
-				      descriptionString);
-    sms->addSubsession(MPEG2TransportFileServerMediaSubsession
-		       ::createNew(*env, inputFileName, indexFileName, reuseFirstSource));
-    rtspServer->addServerMediaSession(sms);
-
-    announceStream(rtspServer, sms, streamName, inputFileName);
-  }
-
-  // An AAC audio stream (ADTS-format file):
-  {
-    char const* streamName = "aacAudioTest";
-    char const* inputFileName = "test.aac";
-    ServerMediaSession* sms
-      = ServerMediaSession::createNew(*env, streamName, streamName,
-				      descriptionString);
-    sms->addSubsession(ADTSAudioFileServerMediaSubsession
-		       ::createNew(*env, inputFileName, reuseFirstSource));
-    rtspServer->addServerMediaSession(sms);
-
-    announceStream(rtspServer, sms, streamName, inputFileName);
-  }
-
-  // A DV video stream:
-  {
-    // First, make sure that the RTPSinks' buffers will be large enough to handle the huge size of DV frames (as big as 288000).
-    OutPacketBuffer::maxSize = 300000;
-
-    char const* streamName = "dvVideoTest";
-    char const* inputFileName = "test.dv";
-    ServerMediaSession* sms
-      = ServerMediaSession::createNew(*env, streamName, streamName,
-				      descriptionString);
-    sms->addSubsession(DVVideoFileServerMediaSubsession
-		       ::createNew(*env, inputFileName, reuseFirstSource));
-    rtspServer->addServerMediaSession(sms);
-
-    announceStream(rtspServer, sms, streamName, inputFileName);
-  }
-
-  // A AC3 video elementary stream:
-  {
-    char const* streamName = "ac3AudioTest";
-    char const* inputFileName = "test.ac3";
-    ServerMediaSession* sms
-      = ServerMediaSession::createNew(*env, streamName, streamName,
-				      descriptionString);
-
-    sms->addSubsession(AC3AudioFileServerMediaSubsession
-		       ::createNew(*env, inputFileName, reuseFirstSource));
-
-    rtspServer->addServerMediaSession(sms);
-
-    announceStream(rtspServer, sms, streamName, inputFileName);
-  }
-
-  // A Matroska ('.mkv') file, with video+audio+subtitle streams:
-  {
-    char const* streamName = "matroskaFileTest";
-    char const* inputFileName = "test.mkv";
-    ServerMediaSession* sms
-      = ServerMediaSession::createNew(*env, streamName, streamName,
-				      descriptionString);
-
-    newDemuxWatchVariable = 0;
-    MatroskaFileServerDemux::createNew(*env, inputFileName, onMatroskaDemuxCreation, NULL);
-    env->taskScheduler().doEventLoop(&newDemuxWatchVariable);
-
-    Boolean sessionHasTracks = False;
-    ServerMediaSubsession* smss;
-    while ((smss = matroskaDemux->newServerMediaSubsession()) != NULL) {
-      sms->addSubsession(smss);
-      sessionHasTracks = True;
-    }
-    if (sessionHasTracks) {
-      rtspServer->addServerMediaSession(sms);
-    }
-    // otherwise, because the stream has no tracks, we don't add a ServerMediaSession to the server.
-
-    announceStream(rtspServer, sms, streamName, inputFileName);
-  }
-
-  // A WebM ('.webm') file, with video(VP8)+audio(Vorbis) streams:
-  // (Note: ".webm' files are special types of Matroska files, so we use the same code as the Matroska ('.mkv') file code above.)
-  {
-    char const* streamName = "webmFileTest";
-    char const* inputFileName = "test.webm";
-    ServerMediaSession* sms
-      = ServerMediaSession::createNew(*env, streamName, streamName,
-				      descriptionString);
-
-    newDemuxWatchVariable = 0;
-    MatroskaFileServerDemux::createNew(*env, inputFileName, onMatroskaDemuxCreation, NULL);
-    env->taskScheduler().doEventLoop(&newDemuxWatchVariable);
-
-    Boolean sessionHasTracks = False;
-    ServerMediaSubsession* smss;
-    while ((smss = matroskaDemux->newServerMediaSubsession()) != NULL) {
-      sms->addSubsession(smss);
-      sessionHasTracks = True;
-    }
-    if (sessionHasTracks) {
-      rtspServer->addServerMediaSession(sms);
-    }
-    // otherwise, because the stream has no tracks, we don't add a ServerMediaSession to the server.
-
-    announceStream(rtspServer, sms, streamName, inputFileName);
-  }
-
-  // An Ogg ('.ogg') file, with video and/or audio streams:
-  {
-    char const* streamName = "oggFileTest";
-    char const* inputFileName = "test.ogg";
-    ServerMediaSession* sms
-      = ServerMediaSession::createNew(*env, streamName, streamName,
-				      descriptionString);
-
-    newDemuxWatchVariable = 0;
-    OggFileServerDemux::createNew(*env, inputFileName, onOggDemuxCreation, NULL);
-    env->taskScheduler().doEventLoop(&newDemuxWatchVariable);
-
-    Boolean sessionHasTracks = False;
-    ServerMediaSubsession* smss;
-    while ((smss = oggDemux->newServerMediaSubsession()) != NULL) {
-      sms->addSubsession(smss);
-      sessionHasTracks = True;
-    }
-    if (sessionHasTracks) {
-      rtspServer->addServerMediaSession(sms);
-    }
-    // otherwise, because the stream has no tracks, we don't add a ServerMediaSession to the server.
-
-    announceStream(rtspServer, sms, streamName, inputFileName);
-  }
-
-  // An Opus ('.opus') audio file:
-  // (Note: ".opus' files are special types of Ogg files, so we use the same code as the Ogg ('.ogg') file code above.)
-  {
-    char const* streamName = "opusFileTest";
-    char const* inputFileName = "test.opus";
-    ServerMediaSession* sms
-      = ServerMediaSession::createNew(*env, streamName, streamName,
-				      descriptionString);
-
-    newDemuxWatchVariable = 0;
-    OggFileServerDemux::createNew(*env, inputFileName, onOggDemuxCreation, NULL);
-    env->taskScheduler().doEventLoop(&newDemuxWatchVariable);
-
-    Boolean sessionHasTracks = False;
-    ServerMediaSubsession* smss;
-    while ((smss = oggDemux->newServerMediaSubsession()) != NULL) {
-      sms->addSubsession(smss);
-      sessionHasTracks = True;
-    }
-    if (sessionHasTracks) {
-      rtspServer->addServerMediaSession(sms);
-    }
-    // otherwise, because the stream has no tracks, we don't add a ServerMediaSession to the server.
-
-    announceStream(rtspServer, sms, streamName, inputFileName);
-  }
-
-  // A MPEG-2 Transport Stream, coming from a live UDP (raw-UDP or RTP/UDP) source:
-  {
-    char const* streamName = "mpeg2TransportStreamFromUDPSourceTest";
-    char const* inputAddressStr = "239.255.42.42";
-        // This causes the server to take its input from the stream sent by the "testMPEG2TransportStreamer" demo application.
-        // (Note: If the input UDP source is unicast rather than multicast, then change this to NULL.)
-    portNumBits const inputPortNum = 1234;
-        // This causes the server to take its input from the stream sent by the "testMPEG2TransportStreamer" demo application.
-    Boolean const inputStreamIsRawUDP = False; 
-    ServerMediaSession* sms
-      = ServerMediaSession::createNew(*env, streamName, streamName,
-				      descriptionString);
-    sms->addSubsession(MPEG2TransportUDPServerMediaSubsession
-		       ::createNew(*env, inputAddressStr, inputPortNum, inputStreamIsRawUDP));
-    rtspServer->addServerMediaSession(sms);
-
-    char* url = rtspServer->rtspURL(sms);
-    *env << "\n\"" << streamName << "\" stream, from a UDP Transport Stream input source \n\t(";
-    if (inputAddressStr != NULL) {
-      *env << "IP multicast address " << inputAddressStr << ",";
-    } else {
-      *env << "unicast;";
-    }
-    *env << " port " << inputPortNum << ")\n";
-    *env << "Play this stream using the URL \"" << url << "\"\n";
-    delete[] url;
-  }
-
-  // Also, attempt to create a HTTP server for RTSP-over-HTTP tunneling.
-  // Try first with the default HTTP port (80), and then with the alternative HTTP
-  // port numbers (8000 and 8080).
-
-  if (rtspServer->setUpTunnelingOverHTTP(80) || rtspServer->setUpTunnelingOverHTTP(8000) || rtspServer->setUpTunnelingOverHTTP(8080)) {
-    *env << "\n(We use port " << rtspServer->httpServerPortNum() << " for optional RTSP-over-HTTP tunneling.)\n";
-  } else {
-    *env << "\n(RTSP-over-HTTP tunneling is not available.)\n";
-  }
-
-  env->taskScheduler().doEventLoop(); // does not return
-
-  return 0; // only to prevent compiler warning
-}
-
-static void announceStream(RTSPServer* rtspServer, ServerMediaSession* sms,
-			   char const* streamName, char const* inputFileName) {
-  char* url = rtspServer->rtspURL(sms);
-  UsageEnvironment& env = rtspServer->envir();
-  env << "\n\"" << streamName << "\" stream, from the file \""
-      << inputFileName << "\"\n";
-  env << "Play this stream using the URL \"" << url << "\"\n";
-  delete[] url;
-}
diff --git a/RtspFace/live555/testProgs/testRTSPClient.hpp b/RtspFace/live555/testProgs/testRTSPClient.hpp
index 78088ef..bf37d55 100644
--- a/RtspFace/live555/testProgs/testRTSPClient.hpp
+++ b/RtspFace/live555/testProgs/testRTSPClient.hpp
@@ -20,8 +20,8 @@
 // client application.  For a full-featured RTSP client application - with much more functionality, and many options - see
 // "openRTSP": http://www.live555.com/openRTSP/
 
-#include "liveMedia.hh"
-#include "BasicUsageEnvironment.hh"
+#include <liveMedia.hh>
+#include <BasicUsageEnvironment.hh>
 
 #include <iostream>
 
diff --git a/RtspFace/main.cpp b/RtspFace/main.cpp
index d25eddb..b31af5c 100644
--- a/RtspFace/main.cpp
+++ b/RtspFace/main.cpp
@@ -1,6 +1,7 @@
 #include "PipeLine.h"
 #include "PL_RTSPClient.h"
 #include "PL_H264Decoder.h"
+#include "PL_H264Encoder.h"
 #include "PL_AVFrameYUV420.h"
 
 #include <iostream>
@@ -13,6 +14,7 @@
 	pipeLine.register_elem_creator("PL_RTSPClient", create_PL_RTSPClient);
 	pipeLine.register_elem_creator("PL_H264Decoder", create_PL_H264Decoder);
 	pipeLine.register_elem_creator("PL_AVFrameYUV420", create_PL_AVFrameYUV420);
+	pipeLine.register_elem_creator("PL_H264Encoder", create_PL_H264Encoder);
 	
 	PL_RTSPClient* rtspClient = (PL_RTSPClient*)pipeLine.push_elem("PL_RTSPClient");
 	RTSPConfig rtspConfig;
@@ -28,8 +30,11 @@
 	PL_H264Decoder* h264Decoder = (PL_H264Decoder*)pipeLine.push_elem("PL_H264Decoder");
 	h264Decoder->init(nullptr);
 	
-	PL_AVFrameYUV420* avFrameYUV420 = (PL_AVFrameYUV420*)pipeLine.push_elem("PL_AVFrameYUV420");
-	avFrameYUV420->init(nullptr);
+	//PL_AVFrameYUV420* avFrameYUV420 = (PL_AVFrameYUV420*)pipeLine.push_elem("PL_AVFrameYUV420");
+	//avFrameYUV420->init(nullptr);
+	
+	PL_H264Encoder* h264Encoder = (PL_H264Encoder*)pipeLine.push_elem("PL_H264Encoder");
+	h264Encoder->init(nullptr);
 	
 	while(true)
 	{
diff --git a/RtspFace/make.sh b/RtspFace/make.sh
index 4749d56..4286377 100644
--- a/RtspFace/make.sh
+++ b/RtspFace/make.sh
@@ -2,6 +2,10 @@
 LIVEMEDIA_INC="-I$LIVEMEDIA_BASE/liveMedia/include -I$LIVEMEDIA_BASE/groupsock/include -I$LIVEMEDIA_BASE/UsageEnvironment/include -I$LIVEMEDIA_BASE/BasicUsageEnvironment/include"
 LIVEMEDIA_LIB="-L$LIVEMEDIA_BASE/liveMedia -L$LIVEMEDIA_BASE/groupsock -L$LIVEMEDIA_BASE/UsageEnvironment -L$LIVEMEDIA_BASE/BasicUsageEnvironment -lliveMedia -lgroupsock -lBasicUsageEnvironment -lUsageEnvironment"
 
+LIBX264_BASE=/opt/x264/inst
+LIBX264_INC="-I$LIBX264_BASE/include"
+LIBX264_LIB="-L$LIBX264_BASE/lib -lx264"
+
 FFMPEG_BASE=/opt/ffmpeg-3.2.2/inst
 FFMPEG_INC="-I$FFMPEG_BASE/include"
 FFMPEG_LIB="-L$FFMPEG_BASE/lib -lavutil -lavformat -lswresample -lavcodec"
@@ -15,7 +19,7 @@
 LIBYUV_LIB="-L$LIBYUV_BASE -lyuv"
 
 CPPFLAGS+="-pthread $LIVEMEDIA_INC $FFMPEG_INC $LIBBASE64_INC $LIBYUV_INC"
-LDFLAGS+="-pthread $LIVEMEDIA_LIB $FFMPEG_LIB $LIBBASE64_LIB $LIBYUV_LIB"
+LDFLAGS+="-pthread $LIVEMEDIA_LIB $FFMPEG_LIB $LIBBASE64_LIB $LIBYUV_LIB $LIBX264_LIB"
 
 CFLAGS+="-D__STDC_CONSTANT_MACROS"
 
@@ -25,10 +29,11 @@
 g++ -g -c -std=c++11 main.cpp $CFLAGS $CPPFLAGS
 g++ -g -c -std=c++11 PL_RTSPClient.cpp $CFLAGS $CPPFLAGS
 g++ -g -c -std=c++11 PL_H264Decoder.cpp $CFLAGS $CPPFLAGS
-g++ -g -c -std=c++11 PL_AVFrameYUV420.cpp $CFLAGS $CPPFLAGS
 g++ -g -c -std=c++11 PL_AVFrameBGRA.cpp $CFLAGS $CPPFLAGS
+g++ -g -c -std=c++11 PL_AVFrameYUV420.cpp $CFLAGS $CPPFLAGS
+g++ -g -c -std=c++11 PL_H264Encoder.cpp $CFLAGS $CPPFLAGS
 g++ -g -c -std=c++11 PipeLine.cpp $CFLAGS $CPPFLAGS
-g++ -g -std=c++11 main.o PL_RTSPClient.o PL_H264Decoder.o PL_AVFrameYUV420.o PL_AVFrameBGRA.o PipeLine.o $LDFLAGS -o rtsp_face
+g++ -g -std=c++11 main.o PL_RTSPClient.o PL_H264Decoder.o PL_AVFrameYUV420.o PL_AVFrameBGRA.o PL_H264Encoder.o PipeLine.o $LDFLAGS -o rtsp_face
 
-#export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$FFMPEG_BASE/lib
+#export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$LIBX264_BASE/lib:$FFMPEG_BASE/lib
 #./rtsp_face rtsp://admin:admin12345@192.168.1.63:554/h264/ch1/main/av_stream

--
Gitblit v1.8.0