From f19b3d5505fed5f659872c5f6afc68f25b1e661f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 18 Feb 2017 15:22:56 -0500 Subject: [PATCH] create zm_packet --- src/CMakeLists.txt | 2 +- src/zm_ffmpeg_camera.cpp | 46 +++++++++++++++++++++++++++++----------- src/zm_monitor.cpp | 6 ++++-- src/zm_packet.cpp | 44 ++++++++++++++++++++++++++++++++++++++ src/zm_packet.h | 39 ++++++++++++++++++++++++++++++++++ src/zm_packetqueue.cpp | 27 +++++++++++------------ src/zm_packetqueue.h | 14 ++++++------ src/zm_videostore.cpp | 11 ++++++++-- 8 files changed, 150 insertions(+), 39 deletions(-) create mode 100644 src/zm_packet.cpp create mode 100644 src/zm_packet.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e33f0f0bb..a2e9de9cd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,7 +4,7 @@ configure_file(zm_config.h.in "${CMAKE_CURRENT_BINARY_DIR}/zm_config.h" @ONLY) # Group together all the source files that are used by all the binaries (zmc, zma, zmu, zms etc) -set(ZM_BIN_SRC_FILES zm_box.cpp zm_buffer.cpp zm_camera.cpp zm_comms.cpp zm_config.cpp zm_coord.cpp zm_curl_camera.cpp zm.cpp zm_db.cpp zm_logger.cpp zm_event.cpp zm_exception.cpp zm_file_camera.cpp zm_ffmpeg_camera.cpp zm_image.cpp zm_jpeg.cpp zm_libvlc_camera.cpp zm_local_camera.cpp zm_monitor.cpp zm_ffmpeg.cpp zm_mpeg.cpp zm_packetqueue.cpp zm_poly.cpp zm_regexp.cpp zm_remote_camera.cpp zm_remote_camera_http.cpp zm_remote_camera_rtsp.cpp zm_rtp.cpp zm_rtp_ctrl.cpp zm_rtp_data.cpp zm_rtp_source.cpp zm_rtsp.cpp zm_rtsp_auth.cpp zm_sdp.cpp zm_signal.cpp zm_stream.cpp zm_thread.cpp zm_time.cpp zm_timer.cpp zm_user.cpp zm_utils.cpp zm_video.cpp zm_videostore.cpp zm_zone.cpp zm_storage.cpp) +set(ZM_BIN_SRC_FILES zm_box.cpp zm_buffer.cpp zm_camera.cpp zm_comms.cpp zm_config.cpp zm_coord.cpp zm_curl_camera.cpp zm.cpp zm_db.cpp zm_logger.cpp zm_event.cpp zm_exception.cpp zm_file_camera.cpp zm_ffmpeg_camera.cpp zm_image.cpp zm_jpeg.cpp zm_libvlc_camera.cpp zm_local_camera.cpp zm_monitor.cpp zm_ffmpeg.cpp zm_mpeg.cpp zm_packet.cpp zm_packetqueue.cpp zm_poly.cpp zm_regexp.cpp zm_remote_camera.cpp zm_remote_camera_http.cpp zm_remote_camera_rtsp.cpp zm_rtp.cpp zm_rtp_ctrl.cpp zm_rtp_data.cpp zm_rtp_source.cpp zm_rtsp.cpp zm_rtsp_auth.cpp zm_sdp.cpp zm_signal.cpp zm_stream.cpp zm_thread.cpp zm_time.cpp zm_timer.cpp zm_user.cpp zm_utils.cpp zm_video.cpp zm_videostore.cpp zm_zone.cpp zm_storage.cpp) # A fix for cmake recompiling the source files for every target. add_library(zm STATIC ${ZM_BIN_SRC_FILES}) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 799d59b70..07efff42f 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -63,6 +63,7 @@ FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::stri mOpenStart = 0; mReopenThread = 0; videoStore = NULL; + video_last_pts = 0; #if HAVE_LIBSWSCALE mConvertContext = NULL; @@ -645,24 +646,24 @@ Debug(5, "After av_read_frame (%d)", ret ); // Need to write out all the frames from the last keyframe? unsigned int packet_count = 0; - AVPacket *queued_packet; + ZMPacket *queued_packet; while ( ( queued_packet = packetqueue.popPacket() ) ) { + AVPacket *avp = queued_packet->av_packet(); packet_count += 1; //Write the packet to our video store - Debug(2, "Writing queued packet stream: %d KEY %d, remaining (%d)", queued_packet->stream_index, queued_packet->flags & AV_PKT_FLAG_KEY, packetqueue.size() ); - if ( queued_packet->stream_index == mVideoStreamId ) { - ret = videoStore->writeVideoFramePacket( queued_packet ); - } else if ( queued_packet->stream_index == mAudioStreamId ) { - ret = videoStore->writeAudioFramePacket( queued_packet ); + Debug(2, "Writing queued packet stream: %d KEY %d, remaining (%d)", avp->stream_index, avp->flags & AV_PKT_FLAG_KEY, packetqueue.size() ); + if ( avp->stream_index == mVideoStreamId ) { + ret = videoStore->writeVideoFramePacket( avp ); + } else if ( avp->stream_index == mAudioStreamId ) { + ret = videoStore->writeAudioFramePacket( avp ); } else { - Warning("Unknown stream id in queued packet (%d)", queued_packet->stream_index ); + Warning("Unknown stream id in queued packet (%d)", avp->stream_index ); ret = -1; } if ( ret < 0 ) { //Less than zero and we skipped a frame } - zm_av_packet_unref( queued_packet ); - av_free( queued_packet ); + delete queued_packet; } // end while packets in the packetqueue Debug(2, "Wrote %d queued packets", packet_count ); } // end if ! wasRecording @@ -682,7 +683,7 @@ Debug(5, "After av_read_frame (%d)", ret ); packetqueue.clearQueue(); } if ( packet.pts && video_last_pts > packet.pts ) { - Warning( "Clearing queue due to out of order pts"); + Warning( "Clearing queue due to out of order pts packet.pts=%d video_last_pts=%d", packet.pts, video_last_pts ); packetqueue.clearQueue(); } } @@ -706,6 +707,24 @@ Debug(5, "After av_read_frame (%d)", ret ); } } Debug(4, "about to decode video" ); + +#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0) + ret = avcodec_send_packet( mVideoCodecContext, &packet ); + if ( ret < 0 ) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } + ret = avcodec_receive_frame( mVideoCodecContext, mRawFrame ); + if ( ret < 0 ) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } + frameComplete = 1; +# else ret = zm_avcodec_decode_video( mVideoCodecContext, mRawFrame, &frameComplete, &packet ); if ( ret < 0 ) { av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); @@ -713,6 +732,7 @@ Debug(5, "After av_read_frame (%d)", ret ); zm_av_packet_unref( &packet ); continue; } +#endif Debug( 4, "Decoded video packet at frame %d", frameCount ); @@ -728,7 +748,9 @@ Debug(5, "After av_read_frame (%d)", ret ); zm_av_packet_unref( &packet ); return (-1); } - avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height); +// avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height); + av_image_fill_arrays(mFrame->data, mFrame->linesize, directbuffer, imagePixFormat, width, height, 1); + if (sws_scale(mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mVideoCodecContext->height, mFrame->data, mFrame->linesize) < 0) { @@ -758,7 +780,7 @@ Debug(5, "After av_read_frame (%d)", ret ); } } else { #if LIBAVUTIL_VERSION_CHECK(54, 23, 0, 23, 0) - Debug( 3, "Some other stream index %d, %s", packet.stream_index, av_get_media_type_string( mFormatContext->streams[packet.stream_index]->codec->codec_type) ); + Debug( 3, "Some other stream index %d, %s", packet.stream_index, av_get_media_type_string( mFormatContext->streams[packet.stream_index]->codecpar->codec_type) ); #else Debug( 3, "Some other stream index %d", packet.stream_index ); #endif diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 3decdf69f..39efb712d 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1357,6 +1357,7 @@ bool Monitor::Analyse() { if ( event ) { //TODO: We shouldn't have to do this every time. Not sure why it clears itself if this isn't here?? snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile()); + Debug( 3, "Detected new event at (%d.%d)", timestamp->tv_sec,timestamp->tv_usec ); if ( section_length ) { int section_mod = timestamp->tv_sec%section_length; @@ -3029,7 +3030,7 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z ref_image.WriteJpeg( diag_path ); } - ref_image.Delta( comp_image, &delta_image); + ref_image.Delta( comp_image, &delta_image ); if ( config.record_diag_images ) { static char diag_path[PATH_MAX] = ""; @@ -3117,6 +3118,7 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z if ( alarm ) { for ( int n_zone = 0; n_zone < n_zones; n_zone++ ) { Zone *zone = zones[n_zone]; + // Wasn't this zone already checked above? if ( !zone->IsInclusive() ) { continue; } @@ -3151,7 +3153,7 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z zoneSet.insert( zone->Label() ); } } - } // end if alaram or not + } // end if alarm or not } if ( top_score > 0 ) { diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp new file mode 100644 index 000000000..8fbb65cb8 --- /dev/null +++ b/src/zm_packet.cpp @@ -0,0 +1,44 @@ +//ZoneMinder Packet Implementation Class +//Copyright 2017 ZoneMinder LLC +// +//This file is part of ZoneMinder. +// +//ZoneMinder is free software: you can redistribute it and/or modify +//it under the terms of the GNU General Public License as published by +//the Free Software Foundation, either version 3 of the License, or +//(at your option) any later version. +// +//ZoneMinder is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//GNU General Public License for more details. +// +//You should have received a copy of the GNU General Public License +//along with ZoneMinder. If not, see . + + +#include "zm_packet.h" +#include "zm_ffmpeg.h" + +using namespace std; + +ZMPacket::ZMPacket( AVPacket *p ) { + av_init_packet( &packet ); + if ( zm_av_packet_ref( &packet, p ) < 0 ) { + Error("error refing packet"); + } + gettimeofday( ×tamp, NULL ); +} + +ZMPacket::ZMPacket( AVPacket *p, struct timeval *t ) { + av_init_packet( &packet ); + if ( zm_av_packet_ref( &packet, p ) < 0 ) { + Error("error refing packet"); + } + timestamp = *t; +} + +ZMPacket::~ZMPacket() { + zm_av_packet_unref( &packet ); +} + diff --git a/src/zm_packet.h b/src/zm_packet.h new file mode 100644 index 000000000..9fd7ed8ee --- /dev/null +++ b/src/zm_packet.h @@ -0,0 +1,39 @@ +//ZoneMinder Packet Wrapper Class +//Copyright 2017 ZoneMinder LLC +// +//This file is part of ZoneMinder. +// +//ZoneMinder is free software: you can redistribute it and/or modify +//it under the terms of the GNU General Public License as published by +//the Free Software Foundation, either version 3 of the License, or +//(at your option) any later version. +// +//ZoneMinder is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//GNU General Public License for more details. +// +//You should have received a copy of the GNU General Public License +//along with ZoneMinder. If not, see . + + +#ifndef ZM_PACKET_H +#define ZM_PACKET_H + +extern "C" { +#include +} + +class ZMPacket { + public: + + AVPacket packet; + struct timeval timestamp; + public: + AVPacket *av_packet() { return &packet; } + ZMPacket( AVPacket *packet, struct timeval *timestamp ); + ZMPacket( AVPacket *packet ); + ~ZMPacket(); +}; + +#endif /* ZM_PACKET_H */ diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 207053e6e..c38f74c52 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -33,41 +33,38 @@ zm_packetqueue::~zm_packetqueue() { } -bool zm_packetqueue::queuePacket( AVPacket* packet ) { +bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) { + pktQueue.push( zm_packet ); + + return true; +} +bool zm_packetqueue::queuePacket( AVPacket* av_packet ) { - AVPacket *input_ref = (AVPacket *)av_malloc(sizeof(AVPacket)); - av_init_packet( input_ref ); - if ( zm_av_packet_ref( input_ref, packet ) < 0 ) { - Error("error refing packet"); - av_free(input_ref); - return false; - } + ZMPacket *zm_packet = new ZMPacket( av_packet ); - pktQueue.push( input_ref ); + pktQueue.push( zm_packet ); return true; } -AVPacket* zm_packetqueue::popPacket( ) { +ZMPacket* zm_packetqueue::popPacket( ) { if ( pktQueue.empty() ) { return NULL; } - AVPacket *packet = pktQueue.front(); + ZMPacket *packet = pktQueue.front(); pktQueue.pop(); return packet; } void zm_packetqueue::clearQueue() { - AVPacket *packet = NULL; + ZMPacket *packet = NULL; while(!pktQueue.empty()) { packet = pktQueue.front(); pktQueue.pop(); - // If we clear it, then no freeing gets done, whereas when we pop off, we assume that the packet was freed somewhere else. - zm_av_packet_unref( packet ); - av_free( packet ); + delete packet; } } diff --git a/src/zm_packetqueue.h b/src/zm_packetqueue.h index 60a9620a4..730487312 100644 --- a/src/zm_packetqueue.h +++ b/src/zm_packetqueue.h @@ -24,6 +24,7 @@ //#include //#include #include +#include "zm_packet.h" extern "C" { #include @@ -33,18 +34,17 @@ class zm_packetqueue { public: zm_packetqueue(); virtual ~zm_packetqueue(); + bool queuePacket( AVPacket* packet, struct timeval *timestamp ); + bool queuePacket( ZMPacket* packet ); bool queuePacket( AVPacket* packet ); - AVPacket * popPacket( ); - bool popVideoPacket(AVPacket* packet); - bool popAudioPacket(AVPacket* packet); + ZMPacket * popPacket( ); + bool popVideoPacket(ZMPacket* packet); + bool popAudioPacket(ZMPacket* packet); void clearQueue( ); unsigned int size(); private: - std::queue pktQueue; + std::queue pktQueue; }; - - #endif /* ZM_PACKETQUEUE_H */ - diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 586b9165a..b33900c76 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -470,7 +470,11 @@ Debug(1, "Have audio encoder, need to flush it's output" ); int64_t size; while(1) { +#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0) + ret = avcodec_receive_packet( audio_output_context, &pkt ); +#else ret = avcodec_encode_audio2( audio_output_context, &pkt, NULL, &got_packet ); +#endif if (ret < 0) { Error("ERror encoding audio while flushing"); break; @@ -871,8 +875,11 @@ av_frame_get_best_effort_timestamp(output_frame) * Encode the audio frame and store it in the temporary packet. * The output audio stream encoder is used to do this. */ - if (( ret = avcodec_encode_audio2( audio_output_context, &opkt, - output_frame, &data_present )) < 0) { +#if LIBAVCODEC_VERSION_CHECK(58, 0, 0, 0, 0) + if (( ret = avcodec_receive_packet( audio_output_context, &opkt )) < 0 ) { +#else + if (( ret = avcodec_encode_audio2( audio_output_context, &opkt, output_frame, &data_present )) < 0) { +#endif Error( "Could not encode frame (error '%s')", av_make_error_string(ret).c_str()); zm_av_packet_unref(&opkt);