The previous article introduced the "H264 video through the rtmp streaming", the following will explain how to H264 real-time video through the RTSP live.
The realization idea is to send the video stream to the live555, and the live555 to realize the H264 data stream live.
The video capture module sends the H264 data frame to live555 through the FIFO queue. After receiving the client's RTSP playback request, live555 reads the H264 video data from the FIFO and broadcasts it through RTSP. The entire process is shown in the following illustration:
Adjust and modify Live555 mediaserver
Download the live555 source, add four files to the media directory and modify the file live555MediaServer.cpp. The additional four documents are as follows:
Ww_h264videoservermediasubsession.h
Ww_h264videoservermediasubsession.cpp
Ww_h264videosource.h
Ww_h264videosource.cpp
The following is attached with the source code of four files:
Ww_h264videoservermediasubsession.h
#pragma once #include "livemedia.hh" #include "basicusageenvironment.hh" #include "groupsockhelper.hh" #include "Ondema Ndservermediasubsession.hh "#include" ww_h264videosource.h "class Ww_h264videoservermediasubsession:public ondemandservermediasubsession {public:ww_h264videoservermediasubsession (usageenvironment & env, FramedSource *
SOURCE);
~ww_h264videoservermediasubsession (void);
public:virtual Char const * GETAUXSDPLINE (Rtpsink * rtpsink, Framedsource * inputsource); Virtual Framedsource * Createnewstreamsource (unsigned clientsessionid, unsigned & estbitrate); "Estbitrate" is the stream ' s estimated bitrate, in kbps virtual Rtpsink * Createnewrtpsink (Groupsock * rtpgroupsock, U
nsigned Char rtppayloadtypeifdynamic, Framedsource * inputsource);
Static Ww_h264videoservermediasubsession * CREATENEW (usageenvironment & env, Framedsource * source);
static void Afterplayingdummy (void * ptr);
static void Chkforauxsdpline (void * ptr); void ChkforauxsdplinE1 ();
Private:framedsource * M_PSOURCE;
char * m_psdpline;
Rtpsink * M_pdummyrtpsink;
Char M_done; };
Ww_h264videoservermediasubsession.cpp
#include "Ww_h264videoservermediasubsession.h" ww_h264videoservermediasubsession::ww_ H264videoservermediasubsession (Usageenvironment & env, Framedsource * source): Ondemandservermediasubsession (env
, True) {m_psource = source;
M_psdpline = 0;
} ww_h264videoservermediasubsession::~ww_h264videoservermediasubsession (void) {if (m_psdpline) {free (m_pSDPLine); } ww_h264videoservermediasubsession * Ww_h264videoservermediasubsession::createnew (UsageEnvironment & Env,
Framedsource * source) {return new ww_h264videoservermediasubsession (env, source);} Framedsource * Ww_h264videoservermediasubsession::createnewstreamsource (unsigned clientsessionid, unsigned &
Estbitrate) {return h264videostreamframer::createnew (EnviR (), New Ww_h264videosource (EnviR ())); Rtpsink * Ww_h264videoservermediasubsession::createnewrtpsink (Groupsock * rtpgroupsock, unsigned char Rtppayloadtypeifdynamic, Framedsource * inputsource) {return h264videortpsink::createnew (EnviR (), rtpGroupsOck, rtppayloadtypeifdynamic); } Char const * WW_H264VIDEOSERVERMEDIASUBSESSION::GETAUXSDPLINE (Rtpsink * rtpsink, Framedsource * inputsource) {if (m_p
Sdpline) {return m_psdpline;
} M_pdummyrtpsink = Rtpsink;
Mp_dummy_rtpsink->startplaying (*source, Afterplayingdummy, this);
M_pdummyrtpsink->startplaying (*inputsource, 0, 0);
Chkforauxsdpline (this);
M_done = 0;
EnviR (). TaskScheduler (). Doeventloop (&m_done);
M_psdpline = StrDup (M_pdummyrtpsink->auxsdpline ());
M_pdummyrtpsink->stopplaying ();
return m_psdpline; } void Ww_h264videoservermediasubsession::afterplayingdummy (void * ptr) {ww_h264videoservermediasubsession * this = (WW
_h264videoservermediasubsession *) ptr;
This->m_done = 0xFF; } void Ww_h264videoservermediasubsession::chkforauxsdpline (void * ptr) {ww_h264videoservermediasubsession * this = (WW_
H264videoservermediasubsession *) ptr;
This->chkforauxsdpline1 (); } void Ww_h264videoservermediasubsession::chkforauxsdpline1 () {if (M_pdummyrtpsink->auxsdpline ())
{m_done = 0xFF; else {Double delay = 1000.0/(FRAME_PER_SEC); ms int To_delay = delay * 1000;
US nexttask () = EnviR (). TaskScheduler (). Scheduledelayedtask (To_delay, Chkforauxsdpline, this);
}
}
Ww_h264videosource.h
#ifndef _ww_h264videosource_h
#define _WW_H264VIDEOSOURCE_H
#include "livemedia.hh"
#include " Basicusageenvironment.hh "
#include" groupsockhelper.hh "
#include" framedsource.hh "
#define Frame_per_ SEC
class Ww_h264videosource:public Framedsource
{public
:
Ww_h264videosource (usageenvironment & env);
~ww_h264videosource (void);
Public:
virtual void dogetnextframe ();
virtual unsigned int maxframesize () const;
static void GetNextFrame (void * ptr);
void Getframedata ();
Private:
void *m_ptoken;
char *m_pframebuffer;
int m_hfifo;
};
#endif
Ww_h264videosource.cpp
#include "ww_h264videosource.h" #include <stdio.h> #ifdef WIN32 #include <windows.h> #else #include <sys/ types.h> #include <sys/stat.h> #include <string.h> #include <fcntl.h> #include <unistd.h> # Include <limits.h> #endif #define FIFO_NAME "/tmp/h264_fifo" #define BUFFER_SIZE pipe_buf #define Rev_buf_siz E (1024*1024) #ifdef WIN32 #define MSLEEP (ms) sleep (ms) #else #define MSLEEP (ms) Usleep (ms*1000) #endif ww_h264v Ideosource::ww_h264videosource (Usageenvironment & env): Framedsource (env), M_ptoken (0), m_pFrameBuffer (0), m_
Hfifo (0) {M_hfifo = open (fifo_name,o_rdonly);
printf ("[MEDIA SERVER] Open FIFO result = [%d]\n", M_hfifo);
if (M_hfifo = = 1) {return;
} m_pFrameBuffer = new char[rev_buf_size];
if (m_pFrameBuffer = = NULL) {printf ("[MEDIA SERVER] Error malloc data buffer failed\n");
Return
} memset (M_pframebuffer,0,rev_buf_size); } ww_h264videosource::~ww_h264videosource (void) {if (M_hfifo{:: Close (M_HFIFO);
} envir (). TaskScheduler (). Unscheduledelayedtask (M_ptoken);
if (m_pFrameBuffer) {delete[] m_pframebuffer;
m_pFrameBuffer = NULL;
printf ("[MEDIA SERVER] RTSP connection closed\n"); } void Ww_h264videosource::d ogetnextframe () {///per FPS, compute wait time double delay = 1000.0/(FRAME_PER_SEC * 2); ms int To_delay = delay * 1000;
US m_ptoken = EnviR (). TaskScheduler (). Scheduledelayedtask (To_delay, GetNextFrame, this);
} unsigned int ww_h264videosource::maxframesize () const {return 1024*200;}
void Ww_h264videosource::getnextframe (void * ptr) {(Ww_h264videosource *) ptr)->getframedata ();}
void Ww_h264videosource::getframedata () {gettimeofday (&fpresentationtime, 0);
fframesize = 0;
int len = 0;
unsigned char buffer[buffer_size] = {0};
while (len = Read (m_hfifo,buffer,buffer_size)) >0) {memcpy (M_pframebuffer+fframesize,buffer,len);
Fframesize+=len; }//printf ("[MEDIA SERVER] Getframedata len = [%d],fmaxsize =[%d]\n ", fframesize,fmaxsize);
Fill frame Data memcpy (fto,m_pframebuffer,fframesize);
if (Fframesize > fmaxsize) {fnumtruncatedbytes = fframesize-fmaxsize;
Fframesize = fmaxsize;
else {fnumtruncatedbytes = 0;
} aftergetting (this);
}
Modify the Live555MediaServer.cpp file as follows
/********** This library are free software; Can redistribute it and/or modify it under the terms of the GNU lesser General public License as published by the Software Foundation; Either version 2.1 of the License, or (at your option) any later version.
(<HTTP://WWW.GNU.ORG/COPYLEFT/LESSER.HTML>.) This library is distributed in the hope that it'll be useful, but without any WARRANTY; Without even the implied warranty of merchantability or FITNESS for A particular purpose.
The GNU Lesser general public License to more details. You are should have received a copy of the GNU Lesser General public License and this library; If not, write to the free Software Foundation, INC, Wuyi Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ********* *//Copyright (c) 1996-2013, Live Networks, Inc. All rights reserved//LIVE555 Media Server//Main program #include <BasicUsageEnvironment.hh> #include "dynamicrt Spserver.hh "#include" version.hh "#include" WW_h264videosource.h "#include" ww_h264videoservermediasubsession.h "int main (int argc, char** argv) {//Begin by setting
Up our usage environment:taskscheduler* scheduler = basictaskscheduler::createnew ();
usageenvironment* env = basicusageenvironment::createnew (*scheduler);
userauthenticationdatabase* authdb = NULL; #ifdef Access_control//To implement client ACCESS control to the RTSP server, do the FOLLOWING:AUTHDB = new userauthe
Nticationdatabase; Authdb->adduserrecord ("username1", "Password1"); Replace these and real strings//Repeat the above with each <username>, <password> so you wish to Allo
w//access to the server.
#endif//Create the RTSP server:rtspserver* rtspserver = rtspserver::createnew (*env, 554, authdb);
if (Rtspserver = = NULL) {*env << "Failed to create RTSP server:" << env->getresultmsg () << "\ n";
Exit (1);
}//ADD live stream Ww_h264videosource * videosource = 0; Servermediasession * SMS = Servermediasession::createnew (*env, "Live", 0, "ww live test");
Sms->addsubsession (Ww_h264videoservermediasubsession::createnew (*env, VideoSource));
Rtspserver->addservermediasession (SMS);
char * url = rtspserver->rtspurl (SMS);
*env << "Using URL \" "<< url <<" \ \ n ";
delete[] URL;
Run Loop Env->taskscheduler (). Doeventloop ();
Rtspserver->removeservermediasession (SMS);
Medium::close (Rtspserver);
Env->reclaim ();
Delete Scheduler;
return 1;
}
send the H264 video stream Rtspstream
/********************************************************************
filename: RTSPStream.h
Created: 2013-08-01
Author: firehood
Purpose:
live555 H264 Live RTSP /
#pragma once
#include <stdio.h>
#ifdef WIN32
#include <windows.h>
#else
#include <pthread.h>
#endif
#ifdef WIN32
typedef HANDLE Threadhandle;
#define MSLEEP (ms) sleep (ms)
#else
typedef unsigned int SOCKET;
typedef pthread_t Threadhandle;
#define MSLEEP (MS) Usleep (ms*1000)
#endif
#define FILEBUFSIZE (1024 * 1024)
class Crtspstream
{public
:
crtspstream (void);
~crtspstream (void);
Public:
//initialization of
bool Init ();
Uninstall
void UnInit ();
Send H264 file
bool Sendh264file (const char *pfilename);
Send H264 data frame
int sendh264data (const unsigned char *data,unsigned int size);
/******************************************************************** Filename:RTSPStream.cpp created:2013-08-01 Author:firehood Purpose: Realize H264 RTSP live ***************************************************************** through live555 /#include "RTSPStream.h" #ifdef WIN32 #else #include <sys/types.h> #include <sys/stat.h> #include <st
ring.h> #include <fcntl.h> #include <unistd.h> #include <limits.h> #include <errno.h> #endif #define FIFO_NAME "/tmp/h264_fifo" #define buffersize pipe_buf crtspstream::crtspstream (void) {} crtspstream::~c Rtspstream (void) {} bool Crtspstream::init () {if (Access (FIFO_NAME,F_OK) = = 1) {int res = MKFIFO (fifo_name,0777)
;
if (res!= 0) {printf ("[Rtspstream] Create FIFO failed.\n");
return false;
} return true;
} void Crtspstream::uninit () {} bool Crtspstream::sendh264file (const char *pfilename) {if (Pfilename = = NULL) {
return false; } FILE *FP = fopen (pFileName, "RB");
if (!FP) {printf ("[Rtspstream] Error:open file%s failed!", pfilename);
Fseek (FP, 0, Seek_set);
unsigned char *buffer = new unsigned char[filebufsize];
int pos = 0;
while (1) {int readlen = fread (buffer+pos, sizeof (unsigned char), Filebufsize-pos, FP);
if (readlen<=0) {break;
} Readlen+=pos;
int writelen = Sendh264data (Buffer,readlen);
if (writelen<=0) {break;
} memcpy (Buffer,buffer+writelen,readlen-writelen);
pos = Readlen-writelen;
Msleep (25);
Fclose (FP);
delete[] buffer;
return true; }//Send H264 data frame int Crtspstream::sendh264data (const unsigned char *data,unsigned int size) {if (data = NULL) {return
0; }//Open pipe with non_block mode int pipe_fd = open (Fifo_name, o_wronly|
O_nonblock);
printf ("[Rtspstream] Open FIFO result = [%d]\n", PIPE_FD);
if (pipe_fd = = 1) {return 0;
int send_size = 0;
int remain_size = size; while (Send_size < size) {int Data_len = (remain_size<buffersize)?
Remain_size:buffersize;
int len = write (Pipe_fd,data+send_size,data_len);
if (len = = 1) {static int resend_conut = 0; if (errno = = Eagain && ++resend_conut<=3) {printf ("[Rtspstream] write FIFO error,resend ...
\ n ");
Continue
} resend_conut = 0;
printf ("[Rtspstream] Write FIFO error,errorcode[%d],send_size[%d]\n", errno,send_size);
Break
else {send_size+= len;
remain_size-= Len;
} close (PIPE_FD);
printf ("[Rtspstream] sendh264data datalen[%d], sendsize = [%d]\n", size,send_size);
return 0;
}
test program Code
#include <stdio.h>
#include "RTSPStream.h"
int main (int argc,char* argv[])
{
Crtspstream Rtspsender;
BOOL BRet = Rtspsender.init ();
Rtspsender.sendh264file ("e:\\ test video \\test.264");
System ("pause");
}