This is an automatic generated email to let you know that the following patch were queued at the http://git.linuxtv.org/cgit.cgi/v4l-utils.git tree:
Subject: v4l2-ctl: add --stream-to/from-hdr options Author: Hans Verkuil <hans.verk...@cisco.com> Date: Sun Jun 24 16:01:25 2018 +0200 It was not possible to stream compressed video to/from a file since the bytesused value was never encoded in the file, so there was no way to reconstruct this. Add new -hdr options that add a header to each plane containing the bytesused value. Signed-off-by: Hans Verkuil <hans.verk...@cisco.com> utils/v4l2-ctl/v4l2-ctl-streaming.cpp | 169 +++++++++++++++++++++------------- utils/v4l2-ctl/v4l2-ctl.cpp | 2 + utils/v4l2-ctl/v4l2-ctl.h | 2 + 3 files changed, 111 insertions(+), 62 deletions(-) --- http://git.linuxtv.org/cgit.cgi/v4l-utils.git/commit/?id=d434b85bc3754ef3e54511ea539957633123911c diff --git a/utils/v4l2-ctl/v4l2-ctl-streaming.cpp b/utils/v4l2-ctl/v4l2-ctl-streaming.cpp index d163e9fd324f..15b1164464ca 100644 --- a/utils/v4l2-ctl/v4l2-ctl-streaming.cpp +++ b/utils/v4l2-ctl/v4l2-ctl-streaming.cpp @@ -48,21 +48,24 @@ static tpg_move_mode stream_out_hor_mode = TPG_MOVE_NONE; static tpg_move_mode stream_out_vert_mode = TPG_MOVE_NONE; static unsigned reqbufs_count_cap = 4; static unsigned reqbufs_count_out = 4; -static char *file_cap; -static char *host_cap; -static unsigned host_port_cap = V4L_STREAM_PORT; -static int host_fd_cap = -1; +static char *file_to; +static bool to_with_hdr; +static char *host_to; +static unsigned host_port_to = V4L_STREAM_PORT; +static int host_fd_to = -1; static unsigned rle_perc; static unsigned rle_perc_count; -static char *file_out; -static char *host_out; -static unsigned host_port_out = V4L_STREAM_PORT; -static int host_fd_out = -1; +static char *file_from; +static bool from_with_hdr; +static char *host_from; +static unsigned host_port_from = V4L_STREAM_PORT; +static int host_fd_from = -1; static struct tpg_data tpg; static unsigned output_field = V4L2_FIELD_NONE; static bool output_field_alt; #define TS_WINDOW 241 +#define FILE_HDR_ID v4l2_fourcc('V', 'h', 'd', 'r') class fps_timestamps { private: @@ -241,6 +244,8 @@ void streaming_usage(void) " --stream-to <file> stream to this file. The default is to discard the\n" " data. If <file> is '-', then the data is written to stdout\n" " and the --silent option is turned on automatically.\n" + " --stream-to-hdr <file> stream to this file. Same as --stream-to, but each\n" + " frame is prefixed by a header. Use for compressed data.\n" " --stream-to-host <hostname[:port]>\n" " stream to this host. The default port is %d.\n" #endif @@ -256,6 +261,8 @@ void streaming_usage(void) " --stream-from <file>\n" " stream from this file. The default is to generate a pattern.\n" " If <file> is '-', then the data is read from stdin.\n" + " --stream-from-hdr <file> stream from this file. Same as --stream-from, but each\n" + " frame is prefixed by a header. Use for compressed data.\n" " --stream-from-host <hostname[:port]>\n" " stream from this host. The default port is %d.\n" " --stream-no-query Do not query and set the DV timings or standard before streaming.\n" @@ -593,18 +600,30 @@ void streaming_cmd(int ch, char *optarg) stream_out_perc_fill = 1; break; case OptStreamTo: - file_cap = optarg; - if (!strcmp(file_cap, "-")) + file_to = optarg; + to_with_hdr = false; + if (!strcmp(file_to, "-")) + options[OptSilent] = true; + break; + case OptStreamToHdr: + file_to = optarg; + to_with_hdr = true; + if (!strcmp(file_to, "-")) options[OptSilent] = true; break; case OptStreamToHost: - host_cap = optarg; + host_to = optarg; break; case OptStreamFrom: - file_out = optarg; + file_from = optarg; + from_with_hdr = false; + break; + case OptStreamFromHdr: + file_from = optarg; + from_with_hdr = true; break; case OptStreamFromHost: - host_out = optarg; + host_from = optarg; break; case OptStreamMmap: case OptStreamUser: @@ -736,7 +755,7 @@ public: static bool fill_buffer_from_file(buffers &b, unsigned idx, FILE *fin) { - if (host_fd_out >= 0) { + if (host_fd_from >= 0) { for (;;) { unsigned packet = read_u32(fin); @@ -806,19 +825,31 @@ static bool fill_buffer_from_file(buffers &b, unsigned idx, FILE *fin) } return true; } + +restart: + if (from_with_hdr && read_u32(fin) != FILE_HDR_ID) { + fprintf(stderr, "Unknown header ID\n"); + return false; + } + for (unsigned j = 0; j < b.num_planes; j++) { void *buf = b.bufs[idx][j]; struct v4l2_plane &p = b.planes[idx][j]; - unsigned sz = fread(buf, 1, p.length, fin); + unsigned len = p.length; + unsigned sz; + if (from_with_hdr) + len = read_u32(fin); + sz = fread(buf, 1, len, fin); if (j == 0 && sz == 0 && stream_loop) { fseek(fin, 0, SEEK_SET); - sz = fread(buf, 1, p.length, fin); + goto restart; } - if (sz == p.length) + p.bytesused = len; + if (sz == len) continue; if (sz) - fprintf(stderr, "%u != %u\n", sz, p.length); + fprintf(stderr, "%u != %u\n", sz, len); // Bail out if we get weird buffer sizes. return false; } @@ -1029,8 +1060,7 @@ static int do_setup_out_buffers(int fd, buffers &b, FILE *fin, bool qbuf) for (unsigned j = 0; j < b.num_planes; j++) { struct v4l2_plane &p = b.planes[i][j]; - p.length = planes[j].length; - buf.m.planes[j].bytesused = planes[j].length; + p.bytesused = p.length = planes[j].length; if (b.memory == V4L2_MEMORY_MMAP) { b.bufs[i][j] = mmap(NULL, p.length, PROT_READ | PROT_WRITE, MAP_SHARED, @@ -1059,10 +1089,13 @@ static int do_setup_out_buffers(int fd, buffers &b, FILE *fin, bool qbuf) } if (fin) fill_buffer_from_file(b, buf.index, fin); + + for (unsigned j = 0; j < b.num_planes; j++) + buf.m.planes[j].bytesused = b.planes[i][j].bytesused; } else { b.planes[i][0].length = buf.length; - buf.bytesused = buf.length; + b.planes[i][0].bytesused = buf.length; if (b.memory == V4L2_MEMORY_MMAP) { b.bufs[i][0] = test_mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset); @@ -1088,6 +1121,7 @@ static int do_setup_out_buffers(int fd, buffers &b, FILE *fin, bool qbuf) if (!fin || !fill_buffer_from_file(b, buf.index, fin)) if (can_fill) tpg_fillbuffer(&tpg, stream_out_std, 0, (u8 *)b.bufs[i][0]); + buf.bytesused = b.planes[i][0].bytesused; } if (qbuf) { if (V4L2_TYPE_IS_OUTPUT(buf.type)) @@ -1165,7 +1199,7 @@ static int do_handle_cap(int fd, buffers &b, FILE *fout, int *index, if (fout && (!stream_skip || ignore_count_skip) && !(buf.flags & V4L2_BUF_FLAG_ERROR)) { unsigned rle_size[VIDEO_MAX_PLANES]; - if (host_fd_cap >= 0) { + if (host_fd_to >= 0) { unsigned tot_rle_size = 0; unsigned tot_used = 0; @@ -1186,6 +1220,8 @@ static int do_handle_cap(int fd, buffers &b, FILE *fout, int *index, rle_perc += (tot_rle_size * 100 / tot_used); rle_perc_count++; } + if (to_with_hdr) + write_u32(fout, FILE_HDR_ID); for (unsigned j = 0; j < b.num_planes; j++) { __u32 used = b.is_mplane ? planes[j].bytesused : buf.bytesused; unsigned offset = b.is_mplane ? planes[j].data_offset : 0; @@ -1198,18 +1234,20 @@ static int do_handle_cap(int fd, buffers &b, FILE *fout, int *index, offset = 0; } used -= offset; - if (host_fd_cap >= 0) { + if (host_fd_to >= 0) { write_u32(fout, V4L_STREAM_PACKET_FRAME_VIDEO_SIZE_PLANE_HDR); write_u32(fout, used); write_u32(fout, rle_size[j]); used = rle_size[j]; + } else if (to_with_hdr) { + write_u32(fout, used); } sz = fwrite((char *)b.bufs[buf.index][j] + offset, 1, used, fout); if (sz != used) fprintf(stderr, "%u != %u\n", sz, used); } - if (host_fd_cap >= 0) + if (host_fd_to >= 0) fflush(fout); } if (buf.flags & V4L2_BUF_FLAG_KEYFRAME) @@ -1220,7 +1258,7 @@ static int do_handle_cap(int fd, buffers &b, FILE *fout, int *index, ch = 'B'; if (verbose) { print_concise_buffer(stderr, buf, fps_ts, - host_fd_cap >= 0 ? 100 - rle_perc / rle_perc_count : -1); + host_fd_to >= 0 ? 100 - rle_perc / rle_perc_count : -1); rle_perc_count = rle_perc = 0; } if (index == NULL && test_ioctl(fd, VIDIOC_QBUF, &buf)) @@ -1238,7 +1276,7 @@ static int do_handle_cap(int fd, buffers &b, FILE *fout, int *index, fprintf(stderr, " %.02f fps", fps_ts.fps()); if (dropped) fprintf(stderr, ", dropped buffers: %u", dropped); - if (host_fd_cap >= 0) + if (host_fd_to >= 0) fprintf(stderr, " %d%% compression", 100 - rle_perc / rle_perc_count); rle_perc_count = rle_perc = 0; fprintf(stderr, "\n"); @@ -1334,6 +1372,13 @@ static int do_handle_out(int fd, buffers &b, FILE *fin, struct v4l2_buffer *cap, if (fin && !fill_buffer_from_file(b, buf.index, fin)) return -1; + if (fin && b.is_mplane) { + for (unsigned j = 0; j < b.num_planes; j++) + planes[j].bytesused = b.planes[buf.index][j].bytesused; + } else if (fin) { + buf.bytesused = b.planes[buf.index][0].bytesused; + } + if (!fin && stream_out_refresh) { if (b.is_mplane) { for (unsigned j = 0; j < b.num_planes; j++) @@ -1469,13 +1514,13 @@ recover: } } - if (file_cap) { - if (!strcmp(file_cap, "-")) + if (file_to) { + if (!strcmp(file_to, "-")) fout = stdout; else - fout = fopen(file_cap, "w+"); - } else if (host_cap) { - char *p = strchr(host_cap, ':'); + fout = fopen(file_to, "w+"); + } else if (host_to) { + char *p = strchr(host_to, ':'); struct sockaddr_in serv_addr; struct hostent *server; struct v4l2_format fmt = { }; @@ -1493,17 +1538,17 @@ recover: cropcap.pixelaspect.denominator = 1; } if (p) { - host_port_cap = strtoul(p + 1, 0L, 0); + host_port_to = strtoul(p + 1, 0L, 0); *p = '\0'; } - host_fd_cap = socket(AF_INET, SOCK_STREAM, 0); - if (host_fd_cap < 0) { + host_fd_to = socket(AF_INET, SOCK_STREAM, 0); + if (host_fd_to < 0) { fprintf(stderr, "cannot open socket"); exit(0); } - server = gethostbyname(host_cap); + server = gethostbyname(host_to); if (server == NULL) { - fprintf(stderr, "no such host %s\n", host_cap); + fprintf(stderr, "no such host %s\n", host_to); exit(0); } memset((char *)&serv_addr, 0, sizeof(serv_addr)); @@ -1511,12 +1556,12 @@ recover: memcpy((char *)&serv_addr.sin_addr.s_addr, (char *)server->h_addr, server->h_length); - serv_addr.sin_port = htons(host_port_cap); - if (connect(host_fd_cap, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { + serv_addr.sin_port = htons(host_port_to); + if (connect(host_fd_to, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { fprintf(stderr, "could not connect\n"); exit(0); } - fout = fdopen(host_fd_cap, "a"); + fout = fdopen(host_fd_to, "a"); write_u32(fout, V4L_STREAM_ID); write_u32(fout, V4L_STREAM_VERSION); write_u32(fout, V4L_STREAM_PACKET_FMT_VIDEO); @@ -1618,7 +1663,7 @@ recover: done: if (fout && fout != stdout) { - if (host_fd_cap >= 0) + if (host_fd_to >= 0) write_u32(fout, V4L_STREAM_PACKET_END); fclose(fout); } @@ -1646,19 +1691,19 @@ static void streaming_set_out(int fd) return; } - if (file_out) { - if (!strcmp(file_out, "-")) + if (file_from) { + if (!strcmp(file_from, "-")) fin = stdin; else - fin = fopen(file_out, "r"); - } else if (host_out) { - char *p = strchr(host_out, ':'); + fin = fopen(file_from, "r"); + } else if (host_from) { + char *p = strchr(host_from, ':'); int listen_fd; socklen_t clilen; struct sockaddr_in serv_addr = {}, cli_addr; if (p) { - host_port_out = strtoul(p + 1, 0L, 0); + host_port_from = strtoul(p + 1, 0L, 0); *p = '\0'; } listen_fd = socket(AF_INET, SOCK_STREAM, 0); @@ -1668,19 +1713,19 @@ static void streaming_set_out(int fd) } serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; - serv_addr.sin_port = htons(host_port_out); + serv_addr.sin_port = htons(host_port_from); if (bind(listen_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { fprintf(stderr, "could not bind\n"); exit(1); } listen(listen_fd, 1); clilen = sizeof(cli_addr); - host_fd_out = accept(listen_fd, (struct sockaddr *)&cli_addr, &clilen); - if (host_fd_out < 0) { + host_fd_from = accept(listen_fd, (struct sockaddr *)&cli_addr, &clilen); + if (host_fd_from < 0) { fprintf(stderr, "could not accept\n"); exit(1); } - fin = fdopen(host_fd_out, "r"); + fin = fdopen(host_fd_from, "r"); if (read_u32(fin) != V4L_STREAM_ID) { fprintf(stderr, "unknown protocol ID\n"); goto done; @@ -1868,18 +1913,18 @@ static void streaming_set_m2m(int fd) sub.type = V4L2_EVENT_EOS; ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub); - if (file_cap) { - if (!strcmp(file_cap, "-")) + if (file_to) { + if (!strcmp(file_to, "-")) file[CAP] = stdout; else - file[CAP] = fopen(file_cap, "w+"); + file[CAP] = fopen(file_to, "w+"); } - if (file_out) { - if (!strcmp(file_out, "-")) + if (file_from) { + if (!strcmp(file_from, "-")) file[OUT] = stdin; else - file[OUT] = fopen(file_out, "r"); + file[OUT] = fopen(file_from, "r"); } if (in.reqbufs(fd, reqbufs_count_cap) || @@ -2039,18 +2084,18 @@ static void streaming_set_cap2out(int fd, int out_fd) return; } - if (file_cap) { - if (!strcmp(file_cap, "-")) + if (file_to) { + if (!strcmp(file_to, "-")) file[CAP] = stdout; else - file[CAP] = fopen(file_cap, "w+"); + file[CAP] = fopen(file_to, "w+"); } - if (file_out) { - if (!strcmp(file_out, "-")) + if (file_from) { + if (!strcmp(file_from, "-")) file[OUT] = stdin; else - file[OUT] = fopen(file_out, "r"); + file[OUT] = fopen(file_from, "r"); } if (in.reqbufs(fd, reqbufs_count_cap) || diff --git a/utils/v4l2-ctl/v4l2-ctl.cpp b/utils/v4l2-ctl/v4l2-ctl.cpp index af04ea051556..5572e6dec40a 100644 --- a/utils/v4l2-ctl/v4l2-ctl.cpp +++ b/utils/v4l2-ctl/v4l2-ctl.cpp @@ -245,12 +245,14 @@ static struct option long_options[] = { {"stream-no-query", no_argument, 0, OptStreamNoQuery}, #ifndef NO_STREAM_TO {"stream-to", required_argument, 0, OptStreamTo}, + {"stream-to-hdr", required_argument, 0, OptStreamToHdr}, {"stream-to-host", required_argument, 0, OptStreamToHost}, #endif {"stream-mmap", optional_argument, 0, OptStreamMmap}, {"stream-user", optional_argument, 0, OptStreamUser}, {"stream-dmabuf", no_argument, 0, OptStreamDmaBuf}, {"stream-from", required_argument, 0, OptStreamFrom}, + {"stream-from-hdr", required_argument, 0, OptStreamFromHdr}, {"stream-from-host", required_argument, 0, OptStreamFromHost}, {"stream-out-pattern", required_argument, 0, OptStreamOutPattern}, {"stream-out-square", no_argument, 0, OptStreamOutSquare}, diff --git a/utils/v4l2-ctl/v4l2-ctl.h b/utils/v4l2-ctl/v4l2-ctl.h index c50c03071eb6..77c60c1db913 100644 --- a/utils/v4l2-ctl/v4l2-ctl.h +++ b/utils/v4l2-ctl/v4l2-ctl.h @@ -193,11 +193,13 @@ enum Option { OptStreamPoll, OptStreamNoQuery, OptStreamTo, + OptStreamToHdr, OptStreamToHost, OptStreamMmap, OptStreamUser, OptStreamDmaBuf, OptStreamFrom, + OptStreamFromHdr, OptStreamFromHost, OptStreamOutPattern, OptStreamOutSquare, _______________________________________________ linuxtv-commits mailing list linuxtv-commits@linuxtv.org https://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits