Add videostore to remote_rtsp, still need to check stream is h264
This commit is contained in:
parent
e76d5ad1cb
commit
78b0a9d0a9
|
@ -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 );
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue