Merge pull request #1130 from inflex/h264-mkv

Fixes for crashes from bad packets to av_interleaved_write_frame
This commit is contained in:
Steve Gilvarry 2015-10-30 23:06:21 +11:00
commit 55fce55518
2 changed files with 73 additions and 21 deletions

View File

@ -33,6 +33,9 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
AVStream *input_st, AVStream *inpaud_st, AVStream *input_st, AVStream *inpaud_st,
int64_t nStartTime) { int64_t nStartTime) {
AVDictionary *pmetadata = NULL;
int dsr;
//store inputs in variables local to class //store inputs in variables local to class
filename = filename_in; filename = filename_in;
format = format_in; format = format_in;
@ -40,13 +43,13 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
keyframeMessage = false; keyframeMessage = false;
keyframeSkipNumber = 0; keyframeSkipNumber = 0;
Info("Opening video storage stream %s\n", filename); Info("Opening video storage stream %s\n", filename);
//Init everything we need //Init everything we need
int ret; int ret;
av_register_all(); av_register_all();
//Allocate the output media context based on the filename of the context
avformat_alloc_output_context2(&oc, NULL, NULL, filename); avformat_alloc_output_context2(&oc, NULL, NULL, filename);
//Couldn't deduce format from filename, trying from format name //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); 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; 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) { if (!video_st) {
Fatal("Unable to create video out stream\n"); 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()); av_make_error_string(ret).c_str());
} }
} }
/* Write the stream header, if any. */ /* Write the stream header, if any. */
ret = avformat_write_header(oc, NULL); ret = avformat_write_header(oc, NULL);
if (ret < 0) { if (ret < 0) {
@ -110,6 +119,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
av_make_error_string(ret).c_str()); av_make_error_string(ret).c_str());
} }
prevDts = 0;
startPts = 0; startPts = 0;
startDts = 0; startDts = 0;
filter_in_rescale_delta_last = AV_NOPTS_VALUE; 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); Info("VideoStore startTime=%d\n",startTime);
} }
VideoStore::~VideoStore(){ VideoStore::~VideoStore(){
/* Write the trailer before close */ /* Write the trailer before close */
av_write_trailer(oc); av_write_trailer(oc);
@ -136,28 +147,48 @@ VideoStore::~VideoStore(){
avformat_free_context(oc); 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){ 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); 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; AVPicture pict;
av_init_packet(&opkt); av_init_packet(&opkt);
//Scale the PTS of the outgoing packet to be the correct time base //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; 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; opkt.pts = AV_NOPTS_VALUE;
}
//Scale the DTS of the outgoing packet to be the correct time base //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); 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 = av_rescale_q(ipkt->dts-startDts, input_st->time_base, video_st->time_base);
}
opkt.dts -= ost_tb_start_time; opkt.dts -= ost_tb_start_time;
opkt.duration = av_rescale_q(ipkt->duration, input_st->time_base, video_st->time_base); opkt.duration = av_rescale_q(ipkt->duration, input_st->time_base, video_st->time_base);
opkt.flags = ipkt->flags; opkt.flags = ipkt->flags;
opkt.pos=-1; opkt.pos=-1;
@ -174,15 +205,33 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt, AVStream *input_st){//, AV
opkt.size = sizeof(AVPicture); opkt.size = sizeof(AVPicture);
opkt.flags |= AV_PKT_FLAG_KEY; opkt.flags |= AV_PKT_FLAG_KEY;
} }
memcpy(&safepkt, &opkt, sizeof(AVPacket));
if ((opkt.data == NULL)||(opkt.size < 1)) {
int ret; Warning("%s:%d: Mangled AVPacket: discarding frame", __FILE__, __LINE__ );
ret = av_interleaved_write_frame(oc, &opkt); dumpPacket(&opkt);
if(ret<0){
Fatal("Error encoding video frame packet: %s\n", av_make_error_string(ret).c_str()); } 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;
av_free_packet(&opkt); 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; return 0;
} }
@ -237,10 +286,10 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt, AVStream *input_st){
int ret; int ret;
ret = av_interleaved_write_frame(oc, &opkt); 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()); Fatal("Error encoding audio frame packet: %s\n", av_make_error_string(ret).c_str());
} }
av_free_packet(&opkt); av_free_packet(&opkt);
return 0; return 0;
} }

View File

@ -7,6 +7,7 @@
class VideoStore { class VideoStore {
private: private:
AVOutputFormat *fmt; AVOutputFormat *fmt;
AVFormatContext *oc; AVFormatContext *oc;
AVStream *video_st; AVStream *video_st;
@ -21,14 +22,16 @@ private:
int64_t startTime; int64_t startTime;
int64_t startPts; int64_t startPts;
int64_t startDts; int64_t startDts;
int64_t prevDts;
int64_t filter_in_rescale_delta_last; int64_t filter_in_rescale_delta_last;
public: public:
VideoStore(const char *filename_in, const char *format_in, AVStream *input_st, AVStream *inpaud_st, int64_t nStartTime); VideoStore(const char *filename_in, const char *format_in, AVStream *input_st, AVStream *inpaud_st, int64_t nStartTime);
~VideoStore(); ~VideoStore();
int writeVideoFramePacket(AVPacket *pkt, AVStream *input_st);//, AVPacket *lastKeyframePkt); int writeVideoFramePacket(AVPacket *pkt, AVStream *input_st);//, AVPacket *lastKeyframePkt);
int writeAudioFramePacket(AVPacket *pkt, AVStream *input_st); int writeAudioFramePacket(AVPacket *pkt, AVStream *input_st);
void dumpPacket( AVPacket *pkt );
}; };
/* /*