The previous article described "H264 video via rtmp stream live", below will explain how to H264 live video live through RTSP.
The realization of the idea is to send the video stream to live555, by live555 to achieve the H264 data stream live.
The video capture module sends the H264 data frame to live555 through a FIFO queue. After receiving the client's RTSP playback request, the live555 begins to read the H264 video data from the FIFO and live it out via RTSP. The entire process is shown in the following diagram:
Adjust and modify Live555 mediaserver
Download the live555 source code, add four files in the media directory and modify the file live555MediaServer.cpp. The four additional files are as follows:
Ww_h264videoservermediasubsession.h
Ww_h264videoservermediasubsession.cpp
Ww_h264videosource.h
Ww_h264videosource.cpp
The following is the source code for four documents:
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 () {//Based on FPS, calculate 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 was 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 2.1 of the License, or (at your option) any later version.
(see
send the Rtspstream of the H264 video stream
/********************************************************************
filename: RTSPStream.h
Created: 2013-08-01
Author: firehood
Purpose: live555 for RTSP live
H264 /
#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 (1024x768 * 1024x768)
class Crtspstream
{public
:
crtspstream (void);
~crtspstream (void);
Public:
//Initialize
bool Init ();
Unload
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: H264 RTSP live ***************************************************************** via 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");
}