diff --git a/utils/v4l2-ctl/v4l2-ctl-streaming.cpp b/utils/v4l2-ctl/v4l2-ctl-streaming.cpp
index cd20dec7..61dd84db 100644
--- a/utils/v4l2-ctl/v4l2-ctl-streaming.cpp
+++ b/utils/v4l2-ctl/v4l2-ctl-streaming.cpp
@@ -78,6 +78,7 @@ static unsigned int composed_width;
 static unsigned int composed_height;
 static bool support_cap_compose;
 static bool support_out_crop;
+static bool in_source_change_event;
 
 #define TS_WINDOW 241
 #define FILE_HDR_ID			v4l2_fourcc('V', 'h', 'd', 'r')
@@ -755,8 +756,11 @@ static void read_write_padded_frame(cv4l_fmt &fmt, unsigned char *buf,
 				    FILE *fpointer, unsigned &sz,
 				    unsigned &len, bool is_read)
 {
-	const struct v4l2_fwht_pixfmt_info *vic_fmt = v4l2_fwht_find_pixfmt(fmt.g_pixelformat());
-	unsigned coded_height = fmt.g_height();
+	const struct v4l2_fwht_pixfmt_info *vic_fmt;
+	const static struct v4l2_fwht_pixfmt_info *old_info =
+		v4l2_fwht_find_pixfmt(fmt.g_pixelformat());
+	static cv4l_fmt old_fmt = fmt;
+	unsigned coded_height;
 	unsigned real_width;
 	unsigned real_height;
 	unsigned char *plane_p = buf;
@@ -770,6 +774,21 @@ static void read_write_padded_frame(cv4l_fmt &fmt, unsigned char *buf,
 		real_height = composed_height;
 	}
 
+	/*
+	 * if the source change event was dequeued but the stream was not yet
+	 * restarted then the current buffers still fit the old resolution so
+	 * we need to save it
+	 */
+	if (in_source_change_event) {
+		vic_fmt = old_info;
+		fmt = old_fmt;
+	} else {
+		vic_fmt = v4l2_fwht_find_pixfmt(fmt.g_pixelformat());
+		old_info = vic_fmt;
+		old_fmt = fmt;
+	}
+
+	coded_height = fmt.g_height();
 	sz = 0;
 	len = real_width * real_height * vic_fmt->sizeimage_mult / vic_fmt->sizeimage_div;
 
@@ -1208,8 +1227,18 @@ static int do_handle_cap(cv4l_fd &fd, cv4l_queue &q, FILE *fout, int *index,
 				     host_fd_to >= 0 ? 100 - comp_perc / comp_perc_count : -1);
 		comp_perc_count = comp_perc = 0;
 	}
-	if (!last_buffer && index == NULL && fd.qbuf(buf))
-		return -1;
+	if (!last_buffer && index == NULL) {
+		/*
+		 * EINVAL in qbuf can happen if this is the last buffer before
+		 * a dynamic resolution change sequence. In this case the buffer
+		 * has the size that fits the old resolution and might not
+		 * fit to the new one.
+		 */
+		if (fd.qbuf(buf) && errno != EINVAL) {
+			fprintf(stderr, "%s: qbuf error\n", __func__);
+			return -1;
+		}
+	}
 	if (index)
 		*index = buf.g_index();
 
@@ -1890,6 +1919,7 @@ static void streaming_set_m2m(cv4l_fd &fd)
 	fd_set *rd_fds = &fds[0]; /* for capture */
 	fd_set *ex_fds = &fds[1]; /* for capture */
 	fd_set *wr_fds = &fds[2]; /* for output */
+	bool cap_streaming = false;
 
 	if (!fd.has_vid_m2m()) {
 		fprintf(stderr, "unsupported m2m stream type\n");
@@ -1920,6 +1950,11 @@ static void streaming_set_m2m(cv4l_fd &fd)
 		is_encoder = !fmt.g_bytesperline();
 	}
 
+	memset(&sub, 0, sizeof(sub));
+	sub.type = V4L2_EVENT_SOURCE_CHANGE;
+	if (fd.subscribe_event(sub))
+		goto done;
+
 	if (file_to) {
 		if (!strcmp(file_to, "-"))
 			file[CAP] = stdout;
@@ -1941,6 +1976,10 @@ static void streaming_set_m2m(cv4l_fd &fd)
 			return;
 		}
 	}
+	enum codec_type codec_type;
+
+	if (get_codec_type(fd, codec_type))
+		goto done;
 
 	if (out.reqbufs(&fd, reqbufs_count_out))
 		goto done;
@@ -1951,8 +1990,9 @@ static void streaming_set_m2m(cv4l_fd &fd)
 	if (fd.streamon(out.g_type()))
 		goto done;
 
-	if (capture_setup(fd, in))
-		goto done;
+	if (codec_type != DECODER)
+		if (capture_setup(fd, in))
+			goto done;
 
 	fps_ts[CAP].determine_field(fd.g_fd(), in.g_type());
 	fps_ts[OUT].determine_field(fd.g_fd(), out.g_type());
@@ -1999,12 +2039,25 @@ static void streaming_set_m2m(cv4l_fd &fd)
 			struct v4l2_event ev;
 
 			while (!fd.dqevent(ev)) {
-				if (ev.type != V4L2_EVENT_EOS)
-					continue;
-				wr_fds = NULL;
-				fprintf(stderr, "EOS");
-				fflush(stderr);
-				break;
+				if (ev.type == V4L2_EVENT_EOS) {
+					wr_fds = NULL;
+					fprintf(stderr, "EOS");
+					fflush(stderr);
+				} else if (ev.type == V4L2_EVENT_SOURCE_CHANGE) {
+					fprintf(stderr, "SOURCE CHANGE\n");
+
+					/*
+					 * if capture is already streaming,
+					 * wait to the a capture buffer with
+					 * LAST_BUFFER flag
+					 */
+					if (cap_streaming) {
+						in_source_change_event = true;
+						continue;
+					}
+					if (capture_setup(fd, in))
+						goto done;
+				}
 			}
 		}
 
@@ -2018,8 +2071,17 @@ static void streaming_set_m2m(cv4l_fd &fd)
 					break;
 				}
 			}
-			if (last_buffer)
-				break;
+			if (last_buffer) {
+				if (in_source_change_event) {
+					in_source_change_event = false;
+					last_buffer = false;
+					if (capture_setup(fd, in))
+						goto done;
+					cap_streaming = true;
+				} else {
+					break;
+				}
+			}
 		}
 
 		if (wr_fds && FD_ISSET(fd.g_fd(), wr_fds)) {
