Add videostore to remote_rtsp, still need to check stream is h264

This commit is contained in:
SteveGilvarry 2015-08-31 21:52:16 +10:00 committed by SteveGilvarry
parent e76d5ad1cb
commit 78b0a9d0a9
2 changed files with 160 additions and 1 deletions

View File

@ -52,11 +52,13 @@ RemoteCameraRtsp::RemoteCameraRtsp( int p_id, const std::string &p_method, const
mFormatContext = NULL; mFormatContext = NULL;
mVideoStreamId = -1; mVideoStreamId = -1;
mAudioStreamId = -1;
mCodecContext = NULL; mCodecContext = NULL;
mCodec = NULL; mCodec = NULL;
mRawFrame = NULL; mRawFrame = NULL;
mFrame = NULL; mFrame = NULL;
frameCount = 0; frameCount = 0;
wasRecording = false;
#if HAVE_LIBSWSCALE #if HAVE_LIBSWSCALE
mConvertContext = NULL; mConvertContext = NULL;
@ -364,6 +366,157 @@ int RemoteCameraRtsp::Capture( Image &image )
return (0) ; return (0) ;
} }
//Function to handle capture and store
int RemoteCameraRtsp::CaptureAndRecord( Image &image, bool recording, char* event_file )
{
AVPacket packet;
uint8_t* directbuffer;
int frameComplete = false;
/* Request a writeable buffer of the target image */
directbuffer = image.WriteBuffer(width, height, colours, subpixelorder);
if(directbuffer == NULL) {
Error("Failed requesting writeable buffer for the captured image.");
return (-1);
}
while ( true )
{
buffer.clear();
if ( !rtspThread->isRunning() )
return (-1);
if ( rtspThread->getFrame( buffer ) )
{
Debug( 3, "Read frame %d bytes", buffer.size() );
Debug( 4, "Address %p", buffer.head() );
Hexdump( 4, buffer.head(), 16 );
if ( !buffer.size() )
return( -1 );
if(mCodecContext->codec_id == AV_CODEC_ID_H264)
{
// SPS and PPS frames should be saved and appended to IDR frames
int nalType = (buffer.head()[3] & 0x1f);
// SPS
if(nalType == 7)
{
lastSps = buffer;
continue;
}
// PPS
else if(nalType == 8)
{
lastPps = buffer;
continue;
}
// IDR
else if(nalType == 5)
{
buffer += lastSps;
buffer += lastPps;
}
}
av_init_packet( &packet );
while ( !frameComplete && buffer.size() > 0 )
{
packet.data = buffer.head();
packet.size = buffer.size();
#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0)
int len = avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, &packet );
#else
int len = avcodec_decode_video( mCodecContext, mRawFrame, &frameComplete, packet.data, packet.size );
#endif
if ( len < 0 )
{
Error( "Error while decoding frame %d", frameCount );
Hexdump( Logger::ERROR, buffer.head(), buffer.size()>256?256:buffer.size() );
buffer.clear();
continue;
}
Debug( 2, "Frame: %d - %d/%d", frameCount, len, buffer.size() );
//if ( buffer.size() < 400 )
//Hexdump( 0, buffer.head(), buffer.size() );
buffer -= len;
}
if ( frameComplete ) {
Debug( 3, "Got frame %d", frameCount );
avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height);
//Video recording
if(recording && !wasRecording){
//Instantiate the video storage module
videoStore = new VideoStore((const char *)event_file, "mp4", mFormatContext->streams[mVideoStreamId],mAudioStreamId==-1?NULL:mFormatContext->streams[mAudioStreamId],startTime);
wasRecording = true;
strcpy(oldDirectory, event_file);
}else if(!recording && wasRecording && videoStore){
Info("Deleting videoStore instance");
delete videoStore;
videoStore = NULL;
}
//The directory we are recording to is no longer tied to the current event. Need to re-init the videostore with the correct directory and start recording again
if(recording && wasRecording && (strcmp(oldDirectory, event_file)!=0) && (packet.flags & AV_PKT_FLAG_KEY) ){ //don't open new videostore until we're on a key frame..would this require an offset adjustment for the event as a result?...if we store our key frame location with the event will that be enough?
Info("Re-starting video storage module");
if(videoStore){
delete videoStore;
videoStore = NULL;
}
videoStore = new VideoStore((const char *)event_file, "mp4", mFormatContext->streams[mVideoStreamId],mAudioStreamId==-1?NULL:mFormatContext->streams[mAudioStreamId],startTime);
strcpy(oldDirectory, event_file);
}
if(videoStore && recording){
//Write the packet to our video store
int ret = videoStore->writeVideoFramePacket(&packet, mFormatContext->streams[mVideoStreamId]);//, &lastKeyframePkt);
if(ret<0){//Less than zero and we skipped a frame
av_free_packet( &packet );
return 0;
}
}
#if HAVE_LIBSWSCALE
if(mConvertContext == NULL) {
if(config.cpu_extensions && sseversion >= 20) {
mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC | SWS_CPU_CAPS_SSE2, NULL, NULL, NULL );
} else {
mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL );
}
if(mConvertContext == NULL)
Fatal( "Unable to create conversion context");
}
if ( sws_scale( mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mCodecContext->height, mFrame->data, mFrame->linesize ) < 0 )
Fatal( "Unable to convert raw format %u to target format %u at frame %d", mCodecContext->pix_fmt, imagePixFormat, frameCount );
#else // HAVE_LIBSWSCALE
Fatal( "You must compile ffmpeg with the --enable-swscale option to use RTSP cameras" );
#endif // HAVE_LIBSWSCALE
frameCount++;
} /* frame complete */
av_free_packet( &packet );
} /* getFrame() */
if(frameComplete)
return (0);
}
return (0) ;
}
int RemoteCameraRtsp::PostCapture() int RemoteCameraRtsp::PostCapture()
{ {
return( 0 ); return( 0 );

View File

@ -26,6 +26,7 @@
#include "zm_utils.h" #include "zm_utils.h"
#include "zm_rtsp.h" #include "zm_rtsp.h"
#include "zm_ffmpeg.h" #include "zm_ffmpeg.h"
#include "zm_videostore.h"
// //
// Class representing 'rtsp' cameras, i.e. those which are // Class representing 'rtsp' cameras, i.e. those which are
@ -55,12 +56,17 @@ protected:
#if HAVE_LIBAVFORMAT #if HAVE_LIBAVFORMAT
AVFormatContext *mFormatContext; AVFormatContext *mFormatContext;
int mVideoStreamId; int mVideoStreamId;
int mAudioStreamId;
AVCodecContext *mCodecContext; AVCodecContext *mCodecContext;
AVCodec *mCodec; AVCodec *mCodec;
AVFrame *mRawFrame; AVFrame *mRawFrame;
AVFrame *mFrame; AVFrame *mFrame;
_AVPIXELFORMAT imagePixFormat; _AVPIXELFORMAT imagePixFormat;
#endif // HAVE_LIBAVFORMAT #endif // HAVE_LIBAVFORMAT
bool wasRecording;
VideoStore *videoStore;
char oldDirectory[4096];
int64_t startTime;
#if HAVE_LIBSWSCALE #if HAVE_LIBSWSCALE
struct SwsContext *mConvertContext; struct SwsContext *mConvertContext;
@ -79,7 +85,7 @@ public:
int PreCapture(); int PreCapture();
int Capture( Image &image ); int Capture( Image &image );
int PostCapture(); int PostCapture();
int CaptureAndRecord( Image &image, bool recording, char* event_directory ) {return(0);}; int CaptureAndRecord( Image &image, bool recording, char* event_directory );
}; };
#endif // ZM_REMOTE_CAMERA_RTSP_H #endif // ZM_REMOTE_CAMERA_RTSP_H