diff options
author | Stanimir Varbanov <stanimir.varbanov@linaro.org> | 2017-08-24 17:36:30 +0300 |
---|---|---|
committer | Stanimir Varbanov <stanimir.varbanov@linaro.org> | 2017-08-24 17:36:30 +0300 |
commit | 6a6534b6e7a2059b3fbe421f1de4cd125f2e5a66 (patch) | |
tree | 0717d3b86f7e2789a84e9f924585f0cb6e8705bd | |
parent | 50a5972b92e0f743743ae4a4e1aabb6de7448873 (diff) | |
download | v4l2-encode-6a6534b6e7a2059b3fbe421f1de4cd125f2e5a66.tar.gz |
Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
-rw-r--r-- | main.c | 92 | ||||
-rw-r--r-- | video.c | 31 | ||||
-rw-r--r-- | video.h | 4 |
3 files changed, 117 insertions, 10 deletions
@@ -113,7 +113,68 @@ static void cleanup(struct instance *i) close(i->out.fd); } -static int save_encoded(struct instance *i, const void *buf, unsigned int size) +//specific to VP8 +static void mem_put_le16(void *vmem, int val) +{ + uint8_t *mem = (uint8_t *)vmem; + + mem[0] = (uint8_t)((val >> 0) & 0xff); + mem[1] = (uint8_t)((val >> 8) & 0xff); +} + +static void mem_put_le32(void *vmem, int val) +{ + uint8_t *mem = (uint8_t *)vmem; + + mem[0] = (uint8_t)((val >> 0) & 0xff); + mem[1] = (uint8_t)((val >> 8) & 0xff); + mem[2] = (uint8_t)((val >> 16) & 0xff); + mem[3] = (uint8_t)((val >> 24) & 0xff); +} + +#define VP8_FOURCC 0x30385056 +#define VP9_FOURCC 0x30395056 + +static void ivf_write_file_header(int outfile, off_t offset, unsigned int width, + unsigned int height, unsigned int fourcc, + int frame_cnt, int timebase_den, + int timebase_num) +{ + char header[32]; + + header[0] = 'D'; + header[1] = 'K'; + header[2] = 'I'; + header[3] = 'F'; + mem_put_le16(header + 4, 0); // version + mem_put_le16(header + 6, 32); // header size + mem_put_le32(header + 8, fourcc); // fourcc + mem_put_le16(header + 12, width); // width + mem_put_le16(header + 14, height); // height + mem_put_le32(header + 16, timebase_den); // rate + mem_put_le32(header + 20, timebase_num); // scale + mem_put_le32(header + 24, frame_cnt); // length + mem_put_le32(header + 28, 0); // unused + + pwrite(outfile, header, 32, offset); +} + +static void ivf_write_frame_header(int outfile, off_t offset, size_t frame_size) +{ + char header[12]; + static int64_t pts = 0; + + mem_put_le32(header, (int)frame_size); + mem_put_le32(header + 4, (int)(pts & 0xFFFFFFFF)); + mem_put_le32(header + 8, (int)(pts >> 32)); + + pwrite(outfile, header, 12, offset); + + pts++; +} + +static int save_encoded(struct instance *i, const void *buf, unsigned int size, + bool is_ivf) { mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; char filename[64]; @@ -125,7 +186,10 @@ static int save_encoded(struct instance *i, const void *buf, unsigned int size) if (!i->save_encoded) return 0; - ret = sprintf(filename, "%s/encoded.%s", i->save_path, ext); + if (is_ivf) + ret = sprintf(filename, "%s/encoded.%s.ivf", i->save_path, ext); + else + ret = sprintf(filename, "%s/encoded.%s", i->save_path, ext); if (ret < 0) { err("sprintf fail (%s)", strerror(errno)); return -1; @@ -142,7 +206,18 @@ static int save_encoded(struct instance *i, const void *buf, unsigned int size) dbg("created file %s", filename); + if (is_ivf) { + ivf_write_file_header(out->fd, out->offs, i->width, i->height, + VP8_FOURCC, 0, 30, 1); + out->offs += 32; + } write: + if (is_ivf) { + dbg("frame_header: %d, %d", out->offs, size); + ivf_write_frame_header(out->fd, out->offs, size); + out->offs += 12; + } + written = pwrite(out->fd, buf, size, out->offs); if (written < 0) { err("cannot write to file (%s)", strerror(errno)); @@ -250,13 +325,15 @@ static void *main_thread_func(void *args) handle_v4l_events(vid); if (revents & (POLLIN | POLLRDNORM)) { - unsigned int bytesused; + unsigned int bytesused, dataoffset; /* capture buffer is ready */ dbg("dequeuing capture buffer"); - ret = video_dequeue_capture(i, &n, &finished, &bytesused); + ret = video_dequeue_capture(i, &n, &finished, + &bytesused, &dataoffset, + NULL); if (ret < 0) goto next_event; @@ -272,8 +349,11 @@ static void *main_thread_func(void *args) vid->total_encoded++; - save_encoded(i, (const void *)vid->cap_buf_addr[n][0], - bytesused); + uint8_t *data = (uint8_t*)vid->cap_buf_addr[n][0]; + data += dataoffset; + + save_encoded(i, (const void *)data, bytesused, + i->codec == V4L2_PIX_FMT_VP8); ret = video_queue_buf_cap(i, n); if (!ret) { @@ -226,7 +226,6 @@ int video_set_control(struct instance *i) if (i->num_bframes && i->num_bframes < 4) { memset(&cntrl, 0, sizeof(cntrl)); cntrl.id = V4L2_CID_MPEG_VIDEO_B_FRAMES; -// cntrl.value = 1; cntrl.value = i->num_bframes; info("setting num b frames: %u", cntrl.value); ret = ioctl(i->video.fd, VIDIOC_S_CTRL, &cntrl); @@ -236,6 +235,29 @@ int video_set_control(struct instance *i) } } + if (i->codec == V4L2_PIX_FMT_HEVC) { + if (i->num_bframes && i->num_bframes < 4) { + memset(&cntrl, 0, sizeof(cntrl)); + cntrl.id = V4L2_CID_MPEG_VIDEO_B_FRAMES; + cntrl.value = i->num_bframes; + info("setting num b frames: %u", cntrl.value); + ret = ioctl(i->video.fd, VIDIOC_S_CTRL, &cntrl); + if (ret) + err("set control - num b frames (%s)", + strerror(errno)); + } + } + + if (i->codec == V4L2_PIX_FMT_VP8) { + memset(&cntrl, 0, sizeof(cntrl)); + cntrl.id = V4L2_CID_MPEG_VIDEO_VPX_PROFILE; + cntrl.value = 2; + info("setting VP8 profile: %u", cntrl.value); + ret = ioctl(i->video.fd, VIDIOC_S_CTRL, &cntrl); + if (ret) + err("set control - profile (%s)", strerror(errno)); + } + #if 0 struct v4l2_ext_controls ctrls; struct v4l2_ext_control ctrl[32]; @@ -435,7 +457,8 @@ int video_dequeue_output(struct instance *i, unsigned int *n) } int video_dequeue_capture(struct instance *i, unsigned int *n, - unsigned int *finished, unsigned int *bytesused) + unsigned int *finished, unsigned int *bytesused, + unsigned int *data_offset, unsigned int *buf_flags) { struct v4l2_buffer buf; struct v4l2_plane planes[CAP_PLANES]; @@ -456,6 +479,10 @@ int video_dequeue_capture(struct instance *i, unsigned int *n, *bytesused = buf.m.planes[0].bytesused; *n = buf.index; + *data_offset = buf.m.planes[0].data_offset; + + if (buf_flags) + *buf_flags = buf.flags; return 0; } @@ -61,8 +61,8 @@ int video_export_buf(struct instance *i, unsigned int index); * dequeued buffer. */ int video_dequeue_output(struct instance *i, unsigned int *n); int video_dequeue_capture(struct instance *i, unsigned int *n, - unsigned int *finished, - unsigned int *bytesused); + unsigned int *finished, unsigned int *bytesused, + unsigned int *data_offset, unsigned int *buf_flags); int video_set_control(struct instance *i); int video_stop(struct instance *i); |