motion: update patches to deal with v4l2m2m separate header mode

This commit is contained in:
Joo Aun Saw 2019-09-05 14:32:36 +10:00
parent 07e318b24f
commit 022ad4e92d
4 changed files with 204 additions and 109 deletions

View File

@ -1,14 +1,49 @@
commit cbf86207346d9f1bc36005c2a6342bacf4bcc3e4
Author: Joo Aun Saw <jasaw@dius.com.au>
Date: Mon Aug 19 16:33:08 2019 +1000
support h264_v4l2m2m encoder
diff --git a/ffmpeg.c b/ffmpeg.c
index 3f731ca..beb87b1 100644
index 3f731ca..7a42d24 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -555,7 +555,9 @@ static int ffmpeg_set_quality(struct ffmpeg *ffmpeg){
@@ -179,6 +179,14 @@ int my_copy_packet(AVPacket *dest_pkt, AVPacket *src_pkt){
#endif
}
/*********************************************/
+void my_free_nal_info(struct ffmpeg *ffmpeg){
+ if (ffmpeg->nal_info) {
+ free(ffmpeg->nal_info);
+ ffmpeg->nal_info = NULL;
+ ffmpeg->nal_info_len = 0;
+ }
+}
+/*********************************************/
/****************************************************************************
****************************************************************************
@@ -409,6 +417,25 @@ static int ffmpeg_encode_video(struct ffmpeg *ffmpeg){
return -1;
}
+ if (ffmpeg->nal_info_separated) {
+ // h264_v4l2m2m has NAL units separated from the first frame, which makes
+ // some players very unhappy.
+ if ((ffmpeg->pkt.pts == 0) && (!(ffmpeg->pkt.flags & AV_PKT_FLAG_KEY))) {
+ my_free_nal_info(ffmpeg);
+ ffmpeg->nal_info_len = ffmpeg->pkt.size;
+ ffmpeg->nal_info = malloc(ffmpeg->nal_info_len);
+ if (ffmpeg->nal_info)
+ memcpy(ffmpeg->nal_info, &ffmpeg->pkt.data[0], ffmpeg->nal_info_len);
+ else
+ ffmpeg->nal_info_len = 0;
+ } else if (ffmpeg->nal_info) {
+ int old_size = ffmpeg->pkt.size;
+ av_grow_packet(&ffmpeg->pkt, ffmpeg->nal_info_len);
+ memmove(&ffmpeg->pkt.data[ffmpeg->nal_info_len], &ffmpeg->pkt.data[0], old_size);
+ memcpy(&ffmpeg->pkt.data[0], ffmpeg->nal_info, ffmpeg->nal_info_len);
+ my_free_nal_info(ffmpeg);
+ }
+ }
return 0;
#elif (LIBAVFORMAT_VERSION_MAJOR >= 55) || ((LIBAVFORMAT_VERSION_MAJOR == 54) && (LIBAVFORMAT_VERSION_MINOR > 6))
@@ -555,7 +582,9 @@ static int ffmpeg_set_quality(struct ffmpeg *ffmpeg){
ffmpeg->quality = 45; // default to 45% quality
av_dict_set(&ffmpeg->opts, "preset", "ultrafast", 0);
av_dict_set(&ffmpeg->opts, "tune", "zerolatency", 0);
@ -19,7 +54,7 @@ index 3f731ca..beb87b1 100644
// H264 OMX encoder quality can only be controlled via bit_rate
// bit_rate = ffmpeg->width * ffmpeg->height * ffmpeg->fps * quality_factor
ffmpeg->quality = (int)(((int64_t)ffmpeg->width * ffmpeg->height * ffmpeg->fps * ffmpeg->quality) >> 7);
@@ -702,7 +708,10 @@ static int ffmpeg_set_codec(struct ffmpeg *ffmpeg){
@@ -702,13 +731,20 @@ static int ffmpeg_set_codec(struct ffmpeg *ffmpeg){
ffmpeg->ctx_codec->height = ffmpeg->height;
ffmpeg->ctx_codec->time_base.num = 1;
ffmpeg->ctx_codec->time_base.den = ffmpeg->fps;
@ -31,12 +66,22 @@ index 3f731ca..beb87b1 100644
ffmpeg->ctx_codec->max_b_frames = 0;
if (strcmp(ffmpeg->codec_name, "ffv1") == 0){
ffmpeg->ctx_codec->strict_std_compliance = -2;
@@ -768,6 +777,65 @@ static int ffmpeg_set_stream(struct ffmpeg *ffmpeg){
ffmpeg->ctx_codec->level = 3;
}
ffmpeg->ctx_codec->flags |= MY_CODEC_FLAG_GLOBAL_HEADER;
+ // h264_v4l2m2m has NAL units separated from the first frame. We need to deal
+ // with it appriopriately later
+ if (strcmp(ffmpeg->codec->name, "h264_v4l2m2m") == 0)
+ ffmpeg->nal_info_separated = 1;
retcd = ffmpeg_set_quality(ffmpeg);
if (retcd < 0){
@@ -768,8 +804,69 @@ static int ffmpeg_set_stream(struct ffmpeg *ffmpeg){
}
+
+static int alloc_video_buffer(AVFrame *frame, int align)
+static int ffmpeg_alloc_video_buffer(AVFrame *frame, int align)
+{
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
+ int ret, i, padded_height;
@ -73,12 +118,14 @@ index 3f731ca..beb87b1 100644
+ frame->buf[0] = av_buffer_alloc(ret + 4*plane_padding);
+ if (!frame->buf[0]) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ av_frame_unref(frame);
+ return ret;
+ }
+ frame->buf[1] = av_buffer_alloc(ret + 4*plane_padding);
+ if (!frame->buf[1]) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ av_frame_unref(frame);
+ return ret;
+ }
+
+ frame->data[0] = frame->buf[0]->data;
@ -88,23 +135,27 @@ index 3f731ca..beb87b1 100644
+ frame->extended_data = frame->data;
+
+ return 0;
+fail:
+ av_frame_unref(frame);
+ return ret;
+}
+
+
static int ffmpeg_set_picture(struct ffmpeg *ffmpeg){
+ int retcd;
+ char errstr[128];
+
ffmpeg->picture = my_frame_alloc();
@@ -789,6 +857,15 @@ static int ffmpeg_set_picture(struct ffmpeg *ffmpeg){
if (!ffmpeg->picture) {
MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, _("could not alloc frame"));
@@ -789,6 +886,17 @@ static int ffmpeg_set_picture(struct ffmpeg *ffmpeg){
ffmpeg->picture->width = ffmpeg->ctx_codec->width;
ffmpeg->picture->height = ffmpeg->ctx_codec->height;
+ // h264_v4l2m2m encoder expects video buffer to be allocated
+ if (strcmp(ffmpeg->codec->name, "h264_v4l2m2m") == 0) {
+ if (alloc_video_buffer(ffmpeg->picture, 32)) {
+ MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, _("could not alloc buffers"));
+ retcd = ffmpeg_alloc_video_buffer(ffmpeg->picture, 32);
+ if (retcd) {
+ av_strerror(retcd, errstr, sizeof(errstr));
+ MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, _("could not alloc buffers %s"), errstr);
+ ffmpeg_free_context(ffmpeg);
+ return -1;
+ }
@ -113,45 +164,70 @@ index 3f731ca..beb87b1 100644
return 0;
}
@@ -1365,9 +1442,38 @@ int ffmpeg_put_image(struct ffmpeg *ffmpeg, struct image_data *img_data, const s
@@ -891,6 +999,12 @@ static int ffmpeg_flush_codec(struct ffmpeg *ffmpeg){
my_packet_unref(ffmpeg->pkt);
return -1;
}
+ // v4l2_m2m encoder uses pts 0 and size 0 to indicate AVERROR_EOF
+ if ((ffmpeg->pkt.pts == 0) || (ffmpeg->pkt.size == 0)) {
+ recv_cd = AVERROR_EOF;
+ my_packet_unref(ffmpeg->pkt);
+ continue;
+ }
retcd = av_write_frame(ffmpeg->oc, &ffmpeg->pkt);
if (retcd < 0) {
MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO
@@ -1339,6 +1453,7 @@ void ffmpeg_close(struct ffmpeg *ffmpeg){
}
}
ffmpeg_free_context(ffmpeg);
+ my_free_nal_info(ffmpeg);
}
#else
@@ -1365,9 +1480,28 @@ int ffmpeg_put_image(struct ffmpeg *ffmpeg, struct image_data *img_data, const s
}
/* Setup pointers and line widths. */
- ffmpeg->picture->data[0] = image;
- ffmpeg->picture->data[1] = image + (ffmpeg->ctx_codec->width * ffmpeg->ctx_codec->height);
- ffmpeg->picture->data[2] = ffmpeg->picture->data[1] + ((ffmpeg->ctx_codec->width * ffmpeg->ctx_codec->height) / 4);
+ // Some encoders look for the image in ffmpeg->picture->buf
+ if (ffmpeg->picture->buf[0] == NULL)
+ ffmpeg->picture->data[0] = image;
+ else
+ memcpy(ffmpeg->picture->data[0], image, ffmpeg->ctx_codec->width * ffmpeg->ctx_codec->height);
+
+ if (ffmpeg->picture->buf[1] == NULL) {
+ // assume YUV420P format
+ ffmpeg->picture->data[1] = image + (ffmpeg->ctx_codec->width * ffmpeg->ctx_codec->height);
+ ffmpeg->picture->data[2] = ffmpeg->picture->data[1] + (ffmpeg->ctx_codec->width * ffmpeg->ctx_codec->height / 4);
+ } else {
+ if (strcmp(ffmpeg->codec->name, "h264_v4l2m2m") == 0) {
+ // assume NV21 format
+ int cr_len = ffmpeg->ctx_codec->width * ffmpeg->ctx_codec->height / 4;
+ int cb_len = cr_len;
+ unsigned char *imagecr = image + (ffmpeg->ctx_codec->width * ffmpeg->ctx_codec->height);
+ unsigned char *imagecb = image + (ffmpeg->ctx_codec->width * ffmpeg->ctx_codec->height) + cr_len;
+ if (ffmpeg->ctx_codec->pix_fmt == AV_PIX_FMT_NV21) {
+ int x;
+ int y;
+ for (y = 0; y < ffmpeg->ctx_codec->height; y++) {
+ for (x = 0; x < ffmpeg->ctx_codec->width/4; x++) {
+ ffmpeg->picture->data[1][y*ffmpeg->ctx_codec->width/2 + x*2] = *imagecb;
+ ffmpeg->picture->data[1][y*ffmpeg->ctx_codec->width/2 + x*2 + 1] = *imagecr;
+ imagecb++;
+ imagecr++;
+ }
+ int x;
+ int y;
+ memcpy(ffmpeg->picture->data[0], image, ffmpeg->ctx_codec->width * ffmpeg->ctx_codec->height);
+ for (y = 0; y < ffmpeg->ctx_codec->height; y++) {
+ for (x = 0; x < ffmpeg->ctx_codec->width/4; x++) {
+ ffmpeg->picture->data[1][y*ffmpeg->ctx_codec->width/2 + x*2] = *imagecb;
+ ffmpeg->picture->data[1][y*ffmpeg->ctx_codec->width/2 + x*2 + 1] = *imagecr;
+ imagecb++;
+ imagecr++;
+ }
+ } else {
+ // assume YUV420P format
+ memcpy(&ffmpeg->picture->data[1][0], imagecr, cr_len);
+ memcpy(&ffmpeg->picture->data[1][cr_len], imagecb, cb_len);
+ }
+ } else {
+ // assume YUV420P format
+ ffmpeg->picture->data[0] = image;
+ ffmpeg->picture->data[1] = image + (ffmpeg->ctx_codec->width * ffmpeg->ctx_codec->height);
+ ffmpeg->picture->data[2] = ffmpeg->picture->data[1] + ((ffmpeg->ctx_codec->width * ffmpeg->ctx_codec->height) / 4);
+ }
ffmpeg->gop_cnt ++;
if (ffmpeg->gop_cnt == ffmpeg->ctx_codec->gop_size ){
diff --git a/ffmpeg.h b/ffmpeg.h
index ca77430..c4ae7bb 100644
--- a/ffmpeg.h
+++ b/ffmpeg.h
@@ -61,6 +61,9 @@ struct ffmpeg {
int high_resolution;
int motion_images;
int passthrough;
+ int nal_info_separated;
+ char *nal_info;
+ int nal_info_len;
};
#else
struct ffmpeg {

View File

@ -0,0 +1,23 @@
commit 0cd12918f93fc6559dad56d176a60ddc3f0844d6
Author: Joo Aun Saw <jasaw@dius.com.au>
Date: Thu Sep 5 14:20:07 2019 +1000
ffmpeg: ensure first frame PTS is zero
diff --git a/ffmpeg.c b/ffmpeg.c
index 7a42d24..665aa00 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -512,7 +512,11 @@ static int ffmpeg_set_pts(struct ffmpeg *ffmpeg, const struct timeval *tv1){
ffmpeg_reset_movie_start_time(ffmpeg, tv1);
pts_interval = 0;
}
- ffmpeg->picture->pts = av_rescale_q(pts_interval,(AVRational){1, 1000000L},ffmpeg->video_st->time_base) + ffmpeg->base_pts;
+ if (ffmpeg->last_pts < 0) {
+ // This is the very first frame, ensure PTS is zero
+ ffmpeg->picture->pts = 0;
+ } else
+ ffmpeg->picture->pts = av_rescale_q(pts_interval,(AVRational){1, 1000000L},ffmpeg->video_st->time_base) + ffmpeg->base_pts;
if (ffmpeg->test_mode == TRUE){
MOTION_LOG(INF, TYPE_ENCODER, NO_ERRNO

View File

@ -1,35 +0,0 @@
commit d1aad9ec2b37560ddf2b2a362e30882adce8fb94
Author: Joo Aun Saw <jasaw@dius.com.au>
Date: Mon Aug 19 16:36:30 2019 +1000
fix h264_v4l2m2m encoder draining error
When h264_v4l2m2m encoder is drained, it sets packet pts and size to
zero rather than returning AVERROR_EOF.
diff --git a/ffmpeg.c b/ffmpeg.c
index beb87b1..a3a8701 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -968,11 +968,16 @@ static int ffmpeg_flush_codec(struct ffmpeg *ffmpeg){
my_packet_unref(ffmpeg->pkt);
return -1;
}
- retcd = av_write_frame(ffmpeg->oc, &ffmpeg->pkt);
- if (retcd < 0) {
- MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO
- ,_("Error writing draining video frame"));
- return -1;
+ // v4l2_m2m encoder uses pts 0 and size 0 to indicate AVERROR_EOF
+ if ((ffmpeg->pkt.pts > 0) && (ffmpeg->pkt.size > 0)) {
+ retcd = av_write_frame(ffmpeg->oc, &ffmpeg->pkt);
+ if (retcd < 0) {
+ MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO
+ ,_("Error writing draining video frame"));
+ return -1;
+ }
+ } else {
+ recv_cd = AVERROR_EOF;
}
}
my_packet_unref(ffmpeg->pkt);

View File

@ -1,19 +1,12 @@
commit b9b521dc5d6179e8570d826e00728130144e3902
Author: Joo Aun Saw <jasaw@dius.com.au>
Date: Tue Aug 27 01:09:43 2019 +1000
ffmpeg: decouple avcodec send and receive
diff --git a/ffmpeg.c b/ffmpeg.c
index 6b5459d..18b2894 100644
index 665aa00..1246fdc 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -378,6 +378,15 @@ static int ffmpeg_get_oformat(struct ffmpeg *ffmpeg){
@@ -386,6 +386,14 @@ static int ffmpeg_get_oformat(struct ffmpeg *ffmpeg){
return 0;
}
+static int ffmpeg_write_packet(struct ffmpeg *ffmpeg){
+
+ if (ffmpeg->tlapse == TIMELAPSE_APPEND) {
+ return ffmpeg_timelapse_append(ffmpeg, ffmpeg->pkt);
+ } else {
@ -24,7 +17,7 @@ index 6b5459d..18b2894 100644
static int ffmpeg_encode_video(struct ffmpeg *ffmpeg){
#if (LIBAVFORMAT_VERSION_MAJOR >= 58) || ((LIBAVFORMAT_VERSION_MAJOR == 57) && (LIBAVFORMAT_VERSION_MINOR >= 41))
@@ -392,21 +401,31 @@ static int ffmpeg_encode_video(struct ffmpeg *ffmpeg){
@@ -400,41 +408,49 @@ static int ffmpeg_encode_video(struct ffmpeg *ffmpeg){
,_("Error sending frame for encoding:%s"),errstr);
return -1;
}
@ -34,7 +27,34 @@ index 6b5459d..18b2894 100644
- av_strerror(retcd, errstr, sizeof(errstr));
- MOTION_LOG(DBG, TYPE_ENCODER, NO_ERRNO
- ,_("Receive packet threw EAGAIN returning -2 code :%s"),errstr);
+
- my_packet_unref(ffmpeg->pkt);
- return -2;
- }
- if (retcd < 0 ){
- av_strerror(retcd, errstr, sizeof(errstr));
- MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO
- ,_("Error receiving encoded packet video:%s"),errstr);
- //Packet is freed upon failure of encoding
- return -1;
- }
-
- if (ffmpeg->nal_info_separated) {
- // h264_v4l2m2m has NAL units separated from the first frame, which makes
- // some players very unhappy.
- if ((ffmpeg->pkt.pts == 0) && (!(ffmpeg->pkt.flags & AV_PKT_FLAG_KEY))) {
- my_free_nal_info(ffmpeg);
- ffmpeg->nal_info_len = ffmpeg->pkt.size;
- ffmpeg->nal_info = malloc(ffmpeg->nal_info_len);
- if (ffmpeg->nal_info)
- memcpy(ffmpeg->nal_info, &ffmpeg->pkt.data[0], ffmpeg->nal_info_len);
- else
- ffmpeg->nal_info_len = 0;
- } else if (ffmpeg->nal_info) {
- int old_size = ffmpeg->pkt.size;
- av_grow_packet(&ffmpeg->pkt, ffmpeg->nal_info_len);
- memmove(&ffmpeg->pkt.data[ffmpeg->nal_info_len], &ffmpeg->pkt.data[0], old_size);
- memcpy(&ffmpeg->pkt.data[0], ffmpeg->nal_info, ffmpeg->nal_info_len);
- my_free_nal_info(ffmpeg);
+ while (retcd >= 0) {
+ av_init_packet(&ffmpeg->pkt);
+ ffmpeg->pkt.data = NULL;
@ -44,13 +64,32 @@ index 6b5459d..18b2894 100644
+ //Buffered packet. Throw special return code
+ my_packet_unref(ffmpeg->pkt);
+ return -2;
+ }
}
+ if (retcd < 0 ){
+ av_strerror(retcd, errstr, sizeof(errstr));
+ MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "Error receiving encoded packet video:%s",errstr);
+ my_packet_unref(ffmpeg->pkt);
+ return -1;
+ } else {
+ if (ffmpeg->nal_info_separated) {
+ // h264_v4l2m2m has NAL units separated from the first frame, which makes
+ // some players very unhappy.
+ if ((ffmpeg->pkt.pts == 0) && (!(ffmpeg->pkt.flags & AV_PKT_FLAG_KEY))) {
+ my_free_nal_info(ffmpeg);
+ ffmpeg->nal_info_len = ffmpeg->pkt.size;
+ ffmpeg->nal_info = malloc(ffmpeg->nal_info_len);
+ if (ffmpeg->nal_info)
+ memcpy(ffmpeg->nal_info, &ffmpeg->pkt.data[0], ffmpeg->nal_info_len);
+ else
+ ffmpeg->nal_info_len = 0;
+ } else if (ffmpeg->nal_info) {
+ int old_size = ffmpeg->pkt.size;
+ av_grow_packet(&ffmpeg->pkt, ffmpeg->nal_info_len);
+ memmove(&ffmpeg->pkt.data[ffmpeg->nal_info_len], &ffmpeg->pkt.data[0], old_size);
+ memcpy(&ffmpeg->pkt.data[0], ffmpeg->nal_info, ffmpeg->nal_info_len);
+ my_free_nal_info(ffmpeg);
+ }
+ }
+ if (ffmpeg_write_packet(ffmpeg) < 0) {
+ MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "Error while writing video frame");
+ my_packet_unref(ffmpeg->pkt);
@ -58,19 +97,11 @@ index 6b5459d..18b2894 100644
+ return -1;
+ }
+ }
my_packet_unref(ffmpeg->pkt);
- return -2;
- }
- if (retcd < 0 ){
- av_strerror(retcd, errstr, sizeof(errstr));
- MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO
- ,_("Error receiving encoded packet video:%s"),errstr);
- //Packet is freed upon failure of encoding
- return -1;
+ my_packet_unref(ffmpeg->pkt);
}
return 0;
@@ -417,11 +436,15 @@ static int ffmpeg_encode_video(struct ffmpeg *ffmpeg){
@@ -444,11 +460,15 @@ static int ffmpeg_encode_video(struct ffmpeg *ffmpeg){
char errstr[128];
int got_packet_ptr;
@ -87,7 +118,7 @@ index 6b5459d..18b2894 100644
return -1;
}
if (got_packet_ptr == 0){
@@ -430,6 +453,15 @@ static int ffmpeg_encode_video(struct ffmpeg *ffmpeg){
@@ -457,6 +477,15 @@ static int ffmpeg_encode_video(struct ffmpeg *ffmpeg){
return -2;
}
@ -103,7 +134,7 @@ index 6b5459d..18b2894 100644
return 0;
#else
@@ -438,6 +470,10 @@ static int ffmpeg_encode_video(struct ffmpeg *ffmpeg){
@@ -465,6 +494,10 @@ static int ffmpeg_encode_video(struct ffmpeg *ffmpeg){
uint8_t *video_outbuf;
int video_outbuf_size;
@ -114,7 +145,7 @@ index 6b5459d..18b2894 100644
video_outbuf_size = (ffmpeg->ctx_codec->width +16) * (ffmpeg->ctx_codec->height +16) * 1;
video_outbuf = mymalloc(video_outbuf_size);
@@ -463,6 +499,17 @@ static int ffmpeg_encode_video(struct ffmpeg *ffmpeg){
@@ -490,6 +523,17 @@ static int ffmpeg_encode_video(struct ffmpeg *ffmpeg){
ffmpeg->pkt.pts = ffmpeg->picture->pts;
ffmpeg->pkt.dts = ffmpeg->pkt.pts;
@ -132,7 +163,7 @@ index 6b5459d..18b2894 100644
free(video_outbuf);
return 0;
@@ -1000,14 +1047,9 @@ static int ffmpeg_flush_codec(struct ffmpeg *ffmpeg){
@@ -1034,14 +1078,9 @@ static int ffmpeg_flush_codec(struct ffmpeg *ffmpeg){
static int ffmpeg_put_frame(struct ffmpeg *ffmpeg, const struct timeval *tv1){
int retcd;
@ -147,7 +178,7 @@ index 6b5459d..18b2894 100644
return 0;
}
@@ -1016,21 +1058,9 @@ static int ffmpeg_put_frame(struct ffmpeg *ffmpeg, const struct timeval *tv1){
@@ -1050,21 +1089,9 @@ static int ffmpeg_put_frame(struct ffmpeg *ffmpeg, const struct timeval *tv1){
if (retcd != -2){
MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, _("Error while encoding picture"));
}