diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index f907da6c5..ef8536fbc 100755 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -33,6 +33,9 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, AVStream *input_st, AVStream *inpaud_st, int64_t nStartTime) { + AVDictionary *pmetadata = NULL; + int dsr; + //store inputs in variables local to class filename = filename_in; format = format_in; @@ -40,13 +43,13 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, keyframeMessage = false; keyframeSkipNumber = 0; + Info("Opening video storage stream %s\n", filename); //Init everything we need int ret; av_register_all(); - //Allocate the output media context based on the filename of the context avformat_alloc_output_context2(&oc, NULL, NULL, filename); //Couldn't deduce format from filename, trying from format name @@ -58,10 +61,15 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, filename, format); } } + + dsr = av_dict_set(&pmetadata, "title", "Zoneminder Security Recording", 0); + if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ ); + + oc->metadata = pmetadata; fmt = oc->oformat; - video_st = avformat_new_stream(oc, input_st->codec->codec); + video_st = avformat_new_stream(oc, input_st->codec->codec); if (!video_st) { Fatal("Unable to create video out stream\n"); } @@ -102,7 +110,8 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, av_make_error_string(ret).c_str()); } } - + + /* Write the stream header, if any. */ ret = avformat_write_header(oc, NULL); if (ret < 0) { @@ -110,6 +119,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, av_make_error_string(ret).c_str()); } + prevDts = 0; startPts = 0; startDts = 0; filter_in_rescale_delta_last = AV_NOPTS_VALUE; @@ -118,6 +128,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, Info("VideoStore startTime=%d\n",startTime); } + VideoStore::~VideoStore(){ /* Write the trailer before close */ av_write_trailer(oc); @@ -136,28 +147,48 @@ VideoStore::~VideoStore(){ avformat_free_context(oc); } + +void VideoStore::dumpPacket( AVPacket *pkt ){ + char b[10240]; + + snprintf(b, sizeof(b), " pts: %lld, dts: %lld, data: %p, size: %d, sindex: %d, dflags: %04x, s-pos: %lld, c-duration: %lld\n" + , pkt->pts + , pkt->dts + , pkt->data + , pkt->size + , pkt->stream_index + , pkt->flags + , pkt->pos + , pkt->convergence_duration + ); + Info("%s:%d:DEBUG: %s", __FILE__, __LINE__, b); +} + int VideoStore::writeVideoFramePacket(AVPacket *ipkt, AVStream *input_st){//, AVPacket *lastKeyframePkt){ int64_t ost_tb_start_time = av_rescale_q(startTime, AV_TIME_BASE_Q, video_st->time_base); - AVPacket opkt; + AVPacket opkt, safepkt; AVPicture pict; av_init_packet(&opkt); - + //Scale the PTS of the outgoing packet to be the correct time base - if (ipkt->pts != AV_NOPTS_VALUE) + if (ipkt->pts != AV_NOPTS_VALUE) { opkt.pts = av_rescale_q(ipkt->pts-startPts, input_st->time_base, video_st->time_base) - ost_tb_start_time; - else + }else { opkt.pts = AV_NOPTS_VALUE; + } //Scale the DTS of the outgoing packet to be the correct time base - if(ipkt->dts == AV_NOPTS_VALUE) + if(ipkt->dts == AV_NOPTS_VALUE) { opkt.dts = av_rescale_q(input_st->cur_dts-startDts, AV_TIME_BASE_Q, video_st->time_base); - else + } else { opkt.dts = av_rescale_q(ipkt->dts-startDts, input_st->time_base, video_st->time_base); + } + opkt.dts -= ost_tb_start_time; - + opkt.duration = av_rescale_q(ipkt->duration, input_st->time_base, video_st->time_base); opkt.flags = ipkt->flags; opkt.pos=-1; @@ -174,15 +205,33 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt, AVStream *input_st){//, AV opkt.size = sizeof(AVPicture); opkt.flags |= AV_PKT_FLAG_KEY; } + + memcpy(&safepkt, &opkt, sizeof(AVPacket)); - - int ret; - ret = av_interleaved_write_frame(oc, &opkt); - if(ret<0){ - Fatal("Error encoding video frame packet: %s\n", av_make_error_string(ret).c_str()); - } - - av_free_packet(&opkt); + if ((opkt.data == NULL)||(opkt.size < 1)) { + Warning("%s:%d: Mangled AVPacket: discarding frame", __FILE__, __LINE__ ); + dumpPacket(&opkt); + + } else if ((prevDts > 0) && (prevDts >= opkt.dts)) { + Warning("%s:%d: DTS out of order: %lld \u226E %lld; discarding frame", __FILE__, __LINE__, prevDts, opkt.dts); + prevDts = opkt.dts; + dumpPacket(&opkt); + + } else { + int ret; + + prevDts = opkt.dts; // Unsure if av_interleaved_write_frame() clobbers opkt.dts when out of order, so storing in advance + ret = av_interleaved_write_frame(oc, &opkt); + if(ret<0){ + // There's nothing we can really do if the frame is rejected, just drop it and get on with the next + Warning("%s:%d: Writing frame [av_interleaved_write_frame()] failed: %s(%d) ", __FILE__, __LINE__, av_make_error_string(ret).c_str(), (ret)); + dumpPacket(&safepkt); + } + } + + + av_free_packet(&opkt); + return 0; } @@ -237,10 +286,10 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt, AVStream *input_st){ int ret; ret = av_interleaved_write_frame(oc, &opkt); - if(ret<0){ + if(ret!=0){ Fatal("Error encoding audio frame packet: %s\n", av_make_error_string(ret).c_str()); } av_free_packet(&opkt); return 0; -} \ No newline at end of file +} diff --git a/src/zm_videostore.h b/src/zm_videostore.h index a0290507b..0d72f42b6 100755 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -7,6 +7,7 @@ class VideoStore { private: + AVOutputFormat *fmt; AVFormatContext *oc; AVStream *video_st; @@ -21,14 +22,16 @@ private: int64_t startTime; int64_t startPts; int64_t startDts; + int64_t prevDts; int64_t filter_in_rescale_delta_last; - + public: VideoStore(const char *filename_in, const char *format_in, AVStream *input_st, AVStream *inpaud_st, int64_t nStartTime); ~VideoStore(); int writeVideoFramePacket(AVPacket *pkt, AVStream *input_st);//, AVPacket *lastKeyframePkt); int writeAudioFramePacket(AVPacket *pkt, AVStream *input_st); + void dumpPacket( AVPacket *pkt ); }; /*