more work
This commit is contained in:
parent
24a8915699
commit
9fa48954db
|
@ -587,7 +587,9 @@ bool EventStream::sendFrame( int delta_us ) {
|
|||
|
||||
static char filepath[PATH_MAX];
|
||||
static struct stat filestat;
|
||||
FILE *fdj = NULL;
|
||||
AVPacket *packet = NULL; // If loading from a container format, then this is the packet
|
||||
Image *image = NULL; // Decoded image if not doing passthrough
|
||||
Image *send_image = NULL; //Output converted image
|
||||
|
||||
// This needs to be abstracted. If we are saving jpgs, then load the capture file. If we are only saving analysis frames, then send that.
|
||||
if ( monitor->GetOptSaveJPEGs() & 1 ) {
|
||||
|
@ -598,18 +600,56 @@ bool EventStream::sendFrame( int delta_us ) {
|
|||
Debug(1, "%s not found, dalling back to capture");
|
||||
snprintf( filepath, sizeof(filepath), Event::capture_file_format, event_data->path, curr_frame_id );
|
||||
}
|
||||
|
||||
} else {
|
||||
} else if ( ! ffmpeg_input ) {
|
||||
Fatal("JPEGS not saved.zms is not capable of streaming jpegs from mp4 yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
#if HAVE_LIBAVCODEC
|
||||
// Whether we need to decode, scale, etc.
|
||||
bool send_raw = ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE));
|
||||
// Or if input type != output type
|
||||
if ( type != STREAM_JPEG )
|
||||
send_raw = false;
|
||||
|
||||
if ( ffmpeg_input ) {
|
||||
packet = ffmpeg_input->read_packet();
|
||||
|
||||
/* If output is jpeg, then must keep going until we get a video frame.
|
||||
*/
|
||||
if ( packet ) {
|
||||
AVFrame *frame = ffmpeg_input->decode_packet( packet );
|
||||
if ( frame ) {
|
||||
uint8_t* directbuffer;
|
||||
image = new Image();
|
||||
|
||||
/* Request a writeable buffer of the target image */
|
||||
directbuffer = image->WriteBuffer( frame->width, frame->height, ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB );
|
||||
if ( directbuffer == NULL ) {
|
||||
Error("Failed requesting writeable buffer for the captured image.");
|
||||
zm_av_packet_unref( packet );
|
||||
return false;
|
||||
}
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
av_image_fill_arrays(frame->data, frame->linesize, directbuffer, (AVPixelFormat)frame->format, frame->width, frame->height, 1);
|
||||
#else
|
||||
avpicture_fill( (AVPicture *)frame, directbuffer, frame->format, frame->width, frame->height);
|
||||
#endif
|
||||
|
||||
} // end if frame
|
||||
} // end if packet
|
||||
send_raw = false;
|
||||
} else {
|
||||
image = new Image( filepath );
|
||||
}
|
||||
// Does conversions, scaling, etc.
|
||||
if ( ! send_raw ) {
|
||||
send_image = prepareImage( image );
|
||||
} else {
|
||||
send_image = image;
|
||||
}
|
||||
|
||||
if ( type == STREAM_MPEG ) {
|
||||
Image image( filepath );
|
||||
|
||||
Image *send_image = prepareImage( &image );
|
||||
|
||||
#if HAVE_LIBAVCODEC
|
||||
if ( !vid_stream ) {
|
||||
vid_stream = new VideoStream( "pipe:", format, bitrate, effective_fps, send_image->Colours(), send_image->SubpixelOrder(), send_image->Width(), send_image->Height() );
|
||||
fprintf( stdout, "Content-type: %s\r\n\r\n", vid_stream->MimeType() );
|
||||
|
@ -619,107 +659,46 @@ bool EventStream::sendFrame( int delta_us ) {
|
|||
} else
|
||||
#endif // HAVE_LIBAVCODEC
|
||||
{
|
||||
static unsigned char temp_img_buffer[ZM_MAX_IMAGE_SIZE];
|
||||
fprintf( stdout, "--ZoneMinderFrame\r\n" );
|
||||
|
||||
static unsigned char temp_img_buffer[ZM_MAX_IMAGE_SIZE];
|
||||
int img_buffer_size = 0;
|
||||
uint8_t *img_buffer = temp_img_buffer;
|
||||
|
||||
bool send_raw = ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE));
|
||||
|
||||
fprintf( stdout, "--ZoneMinderFrame\r\n" );
|
||||
|
||||
if ( type != STREAM_JPEG )
|
||||
send_raw = false;
|
||||
|
||||
if ( send_raw ) {
|
||||
fdj = fopen( filepath, "rb" );
|
||||
if ( !fdj ) {
|
||||
Error( "Can't open %s: %s", filepath, strerror(errno) );
|
||||
if ( ! send_file( filepath ) ) {
|
||||
Error( "Can't send %s: %s", filepath, strerror(errno) );
|
||||
return( false );
|
||||
}
|
||||
#if HAVE_SENDFILE
|
||||
if( fstat(fileno(fdj),&filestat) < 0 ) {
|
||||
Error( "Failed getting information about file %s: %s", filepath, strerror(errno) );
|
||||
return( false );
|
||||
}
|
||||
#else
|
||||
img_buffer_size = fread( img_buffer, 1, sizeof(temp_img_buffer), fdj );
|
||||
#endif
|
||||
} else {
|
||||
Image image( filepath );
|
||||
|
||||
Image *send_image = prepareImage( &image );
|
||||
|
||||
switch( type ) {
|
||||
case STREAM_JPEG :
|
||||
send_image->EncodeJpeg( img_buffer, &img_buffer_size );
|
||||
fprintf( stdout, "Content-Type: image/jpeg\r\n" );
|
||||
break;
|
||||
case STREAM_ZIP :
|
||||
#if HAVE_ZLIB_H
|
||||
unsigned long zip_buffer_size;
|
||||
send_image->Zip( img_buffer, &zip_buffer_size );
|
||||
img_buffer_size = zip_buffer_size;
|
||||
fprintf( stdout, "Content-Type: image/x-rgbz\r\n" );
|
||||
break;
|
||||
#else
|
||||
Error("zlib is required for zipped images. Falling back to raw image");
|
||||
type = STREAM_RAW;
|
||||
#endif // HAVE_ZLIB_H
|
||||
case STREAM_RAW :
|
||||
img_buffer = (uint8_t*)(send_image->Buffer());
|
||||
img_buffer_size = send_image->Size();
|
||||
fprintf( stdout, "Content-Type: image/x-rgb\r\n" );
|
||||
break;
|
||||
default:
|
||||
Fatal( "Unexpected frame type %d", type );
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // end switch type
|
||||
send_buffer( img_buffer, img_buffer_size );
|
||||
|
||||
switch( type ) {
|
||||
case STREAM_JPEG :
|
||||
fprintf( stdout, "Content-Type: image/jpeg\r\n" );
|
||||
break;
|
||||
case STREAM_RAW :
|
||||
fprintf( stdout, "Content-Type: image/x-rgb\r\n" );
|
||||
break;
|
||||
case STREAM_ZIP :
|
||||
fprintf( stdout, "Content-Type: image/x-rgbz\r\n" );
|
||||
break;
|
||||
default :
|
||||
Fatal( "Unexpected frame type %d", type );
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if(send_raw) {
|
||||
#if HAVE_SENDFILE
|
||||
fprintf( stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size );
|
||||
if ( zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size) != (int)filestat.st_size ) {
|
||||
/* sendfile() failed, use standard way instead */
|
||||
img_buffer_size = fread( img_buffer, 1, sizeof(temp_img_buffer), fdj );
|
||||
if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) {
|
||||
Error("Unable to send raw frame %u: %s",curr_frame_id,strerror(errno));
|
||||
return( false );
|
||||
}
|
||||
}
|
||||
#else
|
||||
fprintf( stdout, "Content-Length: %d\r\n\r\n", img_buffer_size );
|
||||
if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) {
|
||||
Error("Unable to send raw frame %u: %s",curr_frame_id,strerror(errno));
|
||||
return( false );
|
||||
}
|
||||
#endif
|
||||
fclose(fdj); /* Close the file handle */
|
||||
} else {
|
||||
fprintf( stdout, "Content-Length: %d\r\n\r\n", img_buffer_size );
|
||||
if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) {
|
||||
Error( "Unable to send stream frame: %s", strerror(errno) );
|
||||
return( false );
|
||||
}
|
||||
}
|
||||
} // endif send_raw or not
|
||||
} // mpeg_output or jpeg
|
||||
|
||||
fprintf( stdout, "\r\n\r\n" );
|
||||
fflush( stdout );
|
||||
}
|
||||
last_frame_sent = TV_2_FLOAT( now );
|
||||
return( true );
|
||||
}
|
||||
|
@ -839,4 +818,55 @@ void EventStream::runStream() {
|
|||
#endif // HAVE_LIBAVCODEC
|
||||
|
||||
closeComms();
|
||||
} // end void EventStream::runStream()
|
||||
|
||||
bool EventStream::send_file( const char * filepath ) {
|
||||
static unsigned char temp_img_buffer[ZM_MAX_IMAGE_SIZE];
|
||||
|
||||
int img_buffer_size = 0;
|
||||
uint8_t *img_buffer = temp_img_buffer;
|
||||
|
||||
FILE *fdj = NULL;
|
||||
fdj = fopen( filepath, "rb" );
|
||||
if ( !fdj ) {
|
||||
Error( "Can't open %s: %s", filepath, strerror(errno) );
|
||||
return false;
|
||||
}
|
||||
bool sent = false;
|
||||
bool size_size = false;
|
||||
|
||||
#if HAVE_SENDFILE
|
||||
static struct stat filestat;
|
||||
if( fstat(fileno(fdj),&filestat) < 0 ) {
|
||||
Error( "Failed getting information about file %s: %s", filepath, strerror(errno) );
|
||||
return false;
|
||||
}
|
||||
fprintf( stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size );
|
||||
size_sent = true;
|
||||
|
||||
if ( ! zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size) != (int)filestat.st_size ) {
|
||||
sent = true;
|
||||
}
|
||||
#endif
|
||||
if ( ! sent ) {
|
||||
img_buffer_size = fread( img_buffer, 1, sizeof(temp_img_buffer), fdj );
|
||||
if ( ! size_sent )
|
||||
fprintf( stdout, "Content-Length: %d\r\n\r\n", img_buffer_size );
|
||||
if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) {
|
||||
Error("Unable to send raw frame %u: %s",curr_frame_id,strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
fclose(fdj); /* Close the file handle */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EventStream::send_buffer( uint8_t* buffer, int size ) {
|
||||
fprintf( stdout, "Content-Length: %d\r\n\r\n", size );
|
||||
if ( fwrite( buffer, size, 1, stdout ) != 1 ) {
|
||||
Error("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -122,6 +122,8 @@ class EventStream : public StreamBase {
|
|||
private:
|
||||
AVCodecContext *input_codec_context;
|
||||
AVCodec *input_codec;
|
||||
bool send_file( const char *file_path );
|
||||
bool send_buffer( uint8_t * buffer, int size );
|
||||
};
|
||||
|
||||
#endif // ZM_EVENTSTREAM_H
|
||||
|
|
|
@ -8,6 +8,7 @@ FFmpeg_Input::FFmpeg_Input() {
|
|||
video_stream_id = -1;
|
||||
audio_stream_id = -1;
|
||||
}
|
||||
|
||||
FFmpeg_Input::~FFmpeg_Input() {
|
||||
}
|
||||
|
||||
|
@ -82,3 +83,74 @@ int FFmpeg_Input::Open( const char *filepath ) {
|
|||
return 0;
|
||||
} // end int FFmpeg::Open( const char * filepath )
|
||||
|
||||
AVPacket * FFmpeg_Input::read_packet() {
|
||||
AVPacket *packet = new AVPacket();
|
||||
if ( 0 > read_packet( packet ) ) {
|
||||
delete packet;
|
||||
packet = NULL;
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
/* I am reserving a 0 return value to mean no error, but also no success */
|
||||
|
||||
int FFmpeg_Input::read_packet( AVPacket *packet ) {
|
||||
int avResult = av_read_frame( input_format_context, packet );
|
||||
char errbuf[AV_ERROR_MAX_STRING_SIZE];
|
||||
if ( avResult < 0 ) {
|
||||
av_strerror(avResult, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
||||
if (
|
||||
// Check if EOF.
|
||||
(avResult == AVERROR_EOF || (input_format_context->pb && input_format_context->pb->eof_reached)) ||
|
||||
// Check for Connection failure.
|
||||
(avResult == -110)
|
||||
) {
|
||||
Info( "av_read_frame returned \"%s\". Reopening stream.", errbuf );
|
||||
//ReopenFfmpeg();
|
||||
}
|
||||
|
||||
Error( "Unable to read packet from stream %d: error %d \"%s\".", packet->stream_index, avResult, errbuf );
|
||||
return( -1 );
|
||||
}
|
||||
Debug( 5, "Got packet from stream %d dts (%d) pts(%d)", packet->stream_index, packet->pts, packet->dts );
|
||||
return 1;
|
||||
}
|
||||
|
||||
AVFrame *FFmpeg_Input::decode_packet( AVPacket *packet ) {
|
||||
AVFrame *frame = new AVFrame();
|
||||
if ( 0 >= decode_packet( packet, frame ) ) {
|
||||
delete frame;
|
||||
frame = NULL;
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
int FFmpeg_Input::decode_packet( AVPacket *packet, AVFrame *frame ) {
|
||||
/* Decoding may take multiple packets. So a return value of 0 means no error, but no frame yet. */
|
||||
char errbuf[AV_ERROR_MAX_STRING_SIZE];
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
int ret = avcodec_send_packet( streams[packet->stream_index].context, packet );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to send packet at frame: %s, continuing", errbuf );
|
||||
zm_av_packet_unref( packet );
|
||||
return ret;
|
||||
}
|
||||
ret = avcodec_receive_frame( streams[packet->stream_index].context, frame );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to send packet at frame: %s, continuing", errbuf );
|
||||
return 0;
|
||||
}
|
||||
# else
|
||||
int frameComplete;
|
||||
ret = zm_avcodec_decode_video( streams[packet->stream_index].context, frame, &frameComplete, packet );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to decode frame at frame: %s, continuing", errbuf );
|
||||
zm_av_packet_unref( packet );
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,11 @@ class FFmpeg_Input {
|
|||
int Open( const char *filename );
|
||||
int Close();
|
||||
|
||||
AVPacket * read_packet();
|
||||
int read_packet( AVPacket *packet );
|
||||
AVFrame * decode_packet( AVPacket *packet );
|
||||
int decode_packet( AVPacket *packet, AVFrame *frame );
|
||||
|
||||
private:
|
||||
typedef struct {
|
||||
AVCodecContext *context;
|
||||
|
|
|
@ -145,6 +145,13 @@ public:
|
|||
|
||||
void setStreamType( StreamType p_type ) {
|
||||
type = p_type;
|
||||
#if ! HAVE_ZLIB_H
|
||||
if ( type == STREAM_ZIP ) {
|
||||
Error("zlib is required for zipped images. Falling back to raw image");
|
||||
type = STREAM_RAW;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
void setStreamFormat( const char *p_format ) {
|
||||
format = p_format;
|
||||
|
|
Loading…
Reference in New Issue