aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.c92
-rw-r--r--video.c31
-rw-r--r--video.h4
3 files changed, 117 insertions, 10 deletions
diff --git a/main.c b/main.c
index 03af7da..65ce2ba 100644
--- a/main.c
+++ b/main.c
@@ -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) {
diff --git a/video.c b/video.c
index e655a38..a5e1a95 100644
--- a/video.c
+++ b/video.c
@@ -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;
}
diff --git a/video.h b/video.h
index b1572c8..30b31d2 100644
--- a/video.h
+++ b/video.h
@@ -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);