Add MJPEG support
authorAmit Makani <amit.makani@ti.com>
Thu, 14 Mar 2019 11:07:04 +0000 (16:37 +0530)
committerDavid Huang <d-huang@ti.com>
Thu, 12 Sep 2019 19:29:02 +0000 (14:29 -0500)
Add support for MJPEG streams.

Signed-off-by: Amit Makani <amit.makani@ti.com>
Signed-off-by: David Huang <d-huang@ti.com>
demux.c
main.c

diff --git a/demux.c b/demux.c
index c457fc61e53fc692b75a73aea4b690f39eca8e9f..f68cb0121f6b33975cdedf509e2d4ae07314e399 100644 (file)
--- a/demux.c
+++ b/demux.c
@@ -82,7 +82,8 @@ static struct demux * open_stream(const char * filename, int *width,
        if ((cc->codec_id != AV_CODEC_ID_H264) &&
            (cc->codec_id != AV_CODEC_ID_MPEG2VIDEO) &&
            (cc->codec_id != AV_CODEC_ID_MPEG4) &&
-           (cc->codec_id != AV_CODEC_ID_HEVC)) {
+           (cc->codec_id != AV_CODEC_ID_HEVC) &&
+           (cc->codec_id != AV_CODEC_ID_MJPEG)) {
                printf("could not open '%s': unsupported codec %d", filename,
                        cc->codec_id);
                return NULL;
diff --git a/main.c b/main.c
index 95a1c1223095b4b24446d542c32dec581cd7bbcf..621029cb24fe061d9e913e8f995163d1908c556b 100644 (file)
--- a/main.c
+++ b/main.c
@@ -319,6 +319,7 @@ static const struct AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
 
 static int drmfd1 = -1;
 #define FMT_NUM_PLANES 1 /* Used when creating V4l2 buffers for capture buffers */
+#define FMT_NUM_MJPEG_PLANES 3 /* Used when creating V4l2 buffers for capture buffers */
 
 /*
  * @bo_handle: drm buffer handle
@@ -430,11 +431,11 @@ static int handle_outbuf(int fd, int index, int rdfd, struct buffer buff,
        return ret;
 }
 
-static int handle_capbuf(int fd, int wrfd, int index, struct buffer buff,
+static int handle_capbuf(int fd, int wrfd, int index, struct buffer buff[],
                int save, struct stream_context *str, struct output_format fmt, int usedrmbuff)
 {
        struct v4l2_buffer buf;
-       struct v4l2_plane buf_planes[1];
+       struct v4l2_plane buf_planes[3];
        int ret = 0;
        int i;
        int h = ALIGN(str->height, HW_ALIGN);
@@ -455,12 +456,12 @@ static int handle_capbuf(int fd, int wrfd, int index, struct buffer buff,
                                                        (i * s), str->width);
                                */
                                for(i=0; i<str->height; i++)
-                                       write(wrfd, buff.mapped + (i * s),
+                                       write(wrfd, buff[index].mapped + (i * s),
                                                        (str->width *
                                                         str->num_bytes_per_pix));
 
                                for(i=0; i<(str->height/2); i++)
-                                       write(wrfd, buff.mapped + (h * s) +
+                                       write(wrfd, buff[index].mapped + (h * s) +
                                                        (i * s),
                                                        (str->width *
                                                         str->num_bytes_per_pix));
@@ -469,17 +470,51 @@ static int handle_capbuf(int fd, int wrfd, int index, struct buffer buff,
                        case (V4L2_PIX_FMT_TI1610):
 #ifdef CC_YUV422PLANAR_TO_NV12
                                for (i = 0; i < str->height; i++)
-                                       write(wrfd, buff.mapped + (i * s),
+                                       write(wrfd, buff[index].mapped + (i * s),
                                                str->width * str->num_bytes_per_pix);
                                for (i = 0; i < str->height; i+=2)
-                                       write(wrfd, buff.mapped + (h * s) + (i * s), str->width * str->num_bytes_per_pix);
+                                       write(wrfd, buff[index].mapped + (h * s) + (i * s), str->width * str->num_bytes_per_pix);
 
 #else
                                for (i = 0; i < str->height; i++)
-                                       write(wrfd, buff.mapped + (i * s),
+                                       write(wrfd, buff[index].mapped + (i * s),
                                                        2* str->width * str->num_bytes_per_pix);
 #endif
                                break;
+                       case V4L2_PIX_FMT_YUV420M:
+
+                               for(i=0; i<str->height; i++)
+                                       write(wrfd, buff[(index*3)].mapped + (i * s),
+                                               (str->width *
+                                                str->num_bytes_per_pix));
+
+
+                               for(i=0; i<(str->height/2); i++)
+                                       write(wrfd, buff[(index*3)+1].mapped + (i * s),
+                                               (str->width *
+                                               str->num_bytes_per_pix) / 2);
+
+                               for(i=0; i<(str->height/2); i++)
+                                       write(wrfd, buff[(index*3)+2].mapped + (i * s),
+                                               (str->width *
+                                               str->num_bytes_per_pix) / 2);
+                               break;
+                       case V4L2_PIX_FMT_YUV422M:
+                               for(i=0; i<str->height; i++)
+                                       write(wrfd, buff[(index*3)].mapped + (i * s),
+                                               (str->width *
+                                                str->num_bytes_per_pix));
+
+                               for(i=0; i<(str->height); i++)
+                                       write(wrfd, buff[(index*3)+1].mapped + (i * s),
+                                               (str->width *
+                                               str->num_bytes_per_pix) / 2);
+
+                               for(i=0; i<(str->height); i++)
+                                       write(wrfd, buff[(index*3)+2].mapped + (i * s),
+                                               (str->width *
+                                               str->num_bytes_per_pix) / 2);
+                               break;
                        default:
                                break;
                }
@@ -488,8 +523,24 @@ static int handle_capbuf(int fd, int wrfd, int index, struct buffer buff,
        memzero(buf);
        memzero(buf_planes[0]);
 
-       buf_planes[0].m.fd = buff.dbuf_fd;
-       buf_planes[0].length = buff.length;
+       if(str->codec == AV_CODEC_ID_MJPEG) {
+               memzero(buf_planes[1]);
+               memzero(buf_planes[2]);
+       }
+
+       if(str->codec == AV_CODEC_ID_MJPEG) {
+               buf_planes[0].m.fd = buff[(index*3)].dbuf_fd;
+               buf_planes[0].length = buff[(index*3)].length;
+
+               buf_planes[1].m.fd = buff[((index*3) + 1)].dbuf_fd;
+               buf_planes[1].length = buff[((index*3) + 1)].length;
+
+               buf_planes[2].m.fd = buff[((index*3) + 2)].dbuf_fd;
+               buf_planes[2].length = buff[((index*3) + 2)].length;
+       } else {
+               buf_planes[0].m.fd = buff[index].dbuf_fd;
+               buf_planes[0].length = buff[index].length;
+       }
 
        buf.index = index;
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
@@ -501,7 +552,10 @@ static int handle_capbuf(int fd, int wrfd, int index, struct buffer buff,
                buf.memory = V4L2_MEMORY_DMABUF;
        }
        buf.m.planes = buf_planes;
-       buf.length = 1;
+       if(str->codec == AV_CODEC_ID_MJPEG)
+               buf.length = 3;
+       else
+               buf.length = 1;
 
        ret = ioctl(fd, VIDIOC_QBUF, &buf);
        if (ret < 0)
@@ -522,7 +576,7 @@ static int mainloop(int fd, int rdfd, int wrfd,
        int type, i, ret = 0;
        uint32_t flags = 0;
        struct v4l2_buffer buf;
-       struct v4l2_plane buf_planes[2];
+       struct v4l2_plane buf_planes[3];
        struct pollfd pfd;
        struct timeval times;
        long curr_time = 0;
@@ -538,9 +592,13 @@ static int mainloop(int fd, int rdfd, int wrfd,
        for (i = 0; i < n_outbufs; i++)
                handle_outbuf(fd, i, rdfd, outbufs[i], str, nframes, 0);
 
-       for (i = 0; i < n_capbufs; i++)
-               handle_capbuf(fd, wrfd, i, capbufs[i], 0, str, fmt, usedrmbuff);
-
+       if(str->codec == AV_CODEC_ID_MJPEG) {
+               for (i = 0; i < (n_capbufs / 3); i++)
+                       handle_capbuf(fd, wrfd, i, capbufs, 0, str, fmt, usedrmbuff);
+       } else {
+               for (i = 0; i < n_capbufs; i++)
+                       handle_capbuf(fd, wrfd, i, capbufs, 0, str, fmt, usedrmbuff);
+       }
        type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
        ret = ioctl(fd, VIDIOC_STREAMON, &type);
        if (ret) {
@@ -584,6 +642,7 @@ static int mainloop(int fd, int rdfd, int wrfd,
                                                        break;
                                                }
                                        } else {
+
                                                handle_outbuf(fd, buf.index, rdfd,
                                                                outbufs[buf.index],
                                                                str, nframes,
@@ -604,7 +663,10 @@ static int mainloop(int fd, int rdfd, int wrfd,
                                                buf.memory = V4L2_MEMORY_DMABUF;
                                        }
                                        buf.m.planes = buf_planes;
-                                       buf.length = 2;
+                                       if(str->codec == AV_CODEC_ID_MJPEG)
+                                               buf.length = 3;
+                                       else
+                                               buf.length = 2;
                                        ret = ioctl(fd, VIDIOC_DQBUF, &buf);
                                        if (ret < 0) {
                                                if (errno != EAGAIN) {
@@ -616,6 +678,7 @@ static int mainloop(int fd, int rdfd, int wrfd,
                                                        break;
                                                }
                                        } else {
+
                                                if (enable_prof) {
                                                        gettimeofday(&times, NULL);
                                                        curr_time =
@@ -631,7 +694,7 @@ static int mainloop(int fd, int rdfd, int wrfd,
                                                if (buf.m.planes[0].bytesused)
                                                        handle_capbuf(fd, wrfd,
                                                                      buf.index,
-                                                                     capbufs[buf.index],
+                                                                     capbufs,
                                                                      1, str,
                                                                      fmt, usedrmbuff);
                                                flags = buf.flags;
@@ -825,6 +888,8 @@ int stream_framelevel_parsing(struct stream_context *str, char *input_file, int
                debug_printf("\n%s: codec: H264",__FUNCTION__);
        if(codec == AV_CODEC_ID_HEVC)
                debug_printf("\n%s: codec format: HEVC\n",__FUNCTION__);
+       if(codec == AV_CODEC_ID_MJPEG)
+               debug_printf("\n%s: codec format: MJPEG\n",__FUNCTION__);
 
        inp_buf_len = (inp_width * inp_height);
 
@@ -892,7 +957,6 @@ static int init_device(int fd, int rdfd,
        int i, j;
        /*for v4l2 based capture buffers*/
        struct v4l2_buffer buffer_cap;
-       struct v4l2_plane buf_planes_cap[FMT_NUM_PLANES];
 
        debug_printf("[fd%d] init_device\n", fd);
 
@@ -907,6 +971,8 @@ static int init_device(int fd, int rdfd,
                fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264;
        if(str->codec == AV_CODEC_ID_HEVC)
                fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_HEVC;
+       if(str->codec == AV_CODEC_ID_MJPEG)
+               fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_MJPEG;
 
        ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
        if (ret != 0) {
@@ -919,13 +985,30 @@ static int init_device(int fd, int rdfd,
 
        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
        fmt.fmt.pix_mp.pixelformat = format.fourcc;
-       fmt.fmt.pix_mp.plane_fmt[0].sizeimage =
-               ((fmt.fmt.pix_mp.width * fmt.fmt.pix_mp.height) *
-                format.size_num) * (str->num_bytes_per_pix) / format.size_den;
-       fmt.fmt.pix_mp.width = ALIGN(str->width, HW_ALIGN);
-       fmt.fmt.pix_mp.height = ALIGN(str->height, HW_ALIGN);
-       fmt.fmt.pix_mp.num_planes = 1;
-       fmt.fmt.pix_mp.plane_fmt[0].bytesperline = ALIGN(str->width, HW_ALIGN) * str->num_bytes_per_pix;
+
+       if(str->codec == AV_CODEC_ID_MJPEG) {
+               fmt.fmt.pix_mp.plane_fmt[0].sizeimage =
+                               ((fmt.fmt.pix_mp.width * fmt.fmt.pix_mp.height) * (str->num_bytes_per_pix));
+               fmt.fmt.pix_mp.plane_fmt[1].sizeimage =
+                               ((fmt.fmt.pix_mp.width * fmt.fmt.pix_mp.height) * (str->num_bytes_per_pix)) / 2;
+               fmt.fmt.pix_mp.plane_fmt[2].sizeimage =
+                               ((fmt.fmt.pix_mp.width * fmt.fmt.pix_mp.height) * (str->num_bytes_per_pix)) / 2;
+
+               fmt.fmt.pix_mp.width = ALIGN(str->width, HW_ALIGN);
+               fmt.fmt.pix_mp.height = ALIGN(str->height, HW_ALIGN);
+               fmt.fmt.pix_mp.num_planes = 3;
+               fmt.fmt.pix_mp.plane_fmt[0].bytesperline = ALIGN(str->width, HW_ALIGN) * str->num_bytes_per_pix;
+               fmt.fmt.pix_mp.plane_fmt[1].bytesperline = ALIGN(str->width, HW_ALIGN) * str->num_bytes_per_pix;
+               fmt.fmt.pix_mp.plane_fmt[2].bytesperline = ALIGN(str->width, HW_ALIGN) * str->num_bytes_per_pix;
+       } else {
+               fmt.fmt.pix_mp.plane_fmt[0].sizeimage =
+                               ((fmt.fmt.pix_mp.width * fmt.fmt.pix_mp.height) *
+                                               format.size_num) * (str->num_bytes_per_pix) / format.size_den;
+               fmt.fmt.pix_mp.width = ALIGN(str->width, HW_ALIGN);
+               fmt.fmt.pix_mp.height = ALIGN(str->height, HW_ALIGN);
+               fmt.fmt.pix_mp.num_planes = 1;
+               fmt.fmt.pix_mp.plane_fmt[0].bytesperline = ALIGN(str->width, HW_ALIGN) * str->num_bytes_per_pix;
+       }
 
        ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
        if (ret) {
@@ -1068,6 +1151,54 @@ static int init_device(int fd, int rdfd,
                *n_capbufs = reqbuf.count;
                /*Creating Capbuffers with v4l2 BUFFERS*/
                /* QUERYBUF on Capture - memory of V4L2_MEMORY_MMAP */
+
+               if(str->codec == AV_CODEC_ID_MJPEG) {
+                       struct v4l2_plane buf_planes_cap[FMT_NUM_MJPEG_PLANES];
+
+                       for (j = 0; j < (*n_capbufs / 3); j++) {
+                               memset(&buffer_cap, 0, sizeof(buffer_cap));
+                               buffer_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+                               buffer_cap.index = j;
+                               buffer_cap.m.planes = buf_planes_cap;
+                               buffer_cap.length = FMT_NUM_MJPEG_PLANES;
+                               buffer_cap.memory = V4L2_MEMORY_MMAP;
+
+
+                               ret = ioctl(fd, VIDIOC_QUERYBUF, &buffer_cap);
+                               if (ret < 0) {
+                                       printf("[fd%d] CANNOT QUERY BUFFERS for Capture ret = %d\n", fd, ret);
+                                       return -1;
+                               }
+                               for (i = 0; i < buffer_cap.length; i++) {
+                               debug_printf("[fd%d] query buf, buffer %p plane %d = %d buffer_cap.length %d buffer_cap.data_offset %d buffer_cap.mem_offset %d\n",
+                                               fd, &buffer_cap, i,buffer_cap.m.planes[i].length,
+                                               buffer_cap.length, buffer_cap.m.planes[i].data_offset,
+                                               buffer_cap.m.planes[i].m.mem_offset);
+
+                               capbufs[(j*3)+i].mapped = mmap(NULL, buffer_cap.m.planes[i].length,
+                                               PROT_READ, MAP_SHARED,
+                                               fd, buffer_cap.m.planes[i].m.mem_offset);
+                               capbufs[(j*3)+i].offset = buffer_cap.m.planes[i].m.mem_offset;
+                               capbufs[(j*3)+i].length = buffer_cap.m.planes[i].length;
+
+                               debug_printf("[fd%d] After mmap -> capbufs[%d].mapped = 0x%p\n",
+                                       fd, (j*3)+i, capbufs[(j*3)+i].mapped);
+
+                               if (MAP_FAILED == capbufs[(j*3)+i].mapped) {
+                                       while (j >= 0) {
+                                               /* Unmap all previous buffers */
+                                               j--;
+                                               munmap(capbufs[(j*3)+i].mapped,
+                                                        fmt.fmt.pix_mp.plane_fmt[0].sizeimage);
+                                                        capbufs[(j*3)+i].mapped = NULL;
+                                       }
+                                       printf("[fd%d] Cant mmap capture buffers Y\n", fd);
+                                       return -1;
+                               }
+                               }
+                       }
+               } else {
+                       struct v4l2_plane buf_planes_cap[FMT_NUM_PLANES];
                for (j = 0; j < *n_capbufs; j++) {
                        memset(&buffer_cap, 0, sizeof(buffer_cap));
                        buffer_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
@@ -1076,6 +1207,7 @@ static int init_device(int fd, int rdfd,
                        buffer_cap.length = FMT_NUM_PLANES;
                        buffer_cap.memory = V4L2_MEMORY_MMAP;
 
+
                        ret = ioctl(fd, VIDIOC_QUERYBUF, &buffer_cap);
                        if (ret < 0) {
                                printf("[fd%d] CANNOT QUERY BUFFERS for Capture ret = %d\n",
@@ -1110,6 +1242,7 @@ static int init_device(int fd, int rdfd,
                                return -1;
                        }
                }
+               }
        } else {
                debug_printf("[fd%d] Setup decoding CAPTURE with VIDIOC_REQBUFS\n", fd);
                debug_printf("[fd%d] buffer(y) size %u buffer(uv) size %u\n",
@@ -1142,8 +1275,8 @@ static int init_device(int fd, int rdfd,
                                printf("[fd%d] failed to create drm buffers\n", fd);
                                return -1;
                        }
-                       debug_printf("[fd%d] Create_DRM_BUFFERS drm_y_buffer[%d].dbuf_fd 0x%x\n",
-                                       fd, i, capbufs[i].dbuf_fd);
+                       debug_printf("[fd%d] Create_DRM_BUFFERS drm_y_buffer[%d].dbuf_fd 0x%x, length %d offset %d\n",
+                                       fd, i, capbufs[i].dbuf_fd, capbufs[i].length, capbufs[i].offset);
                }
        }
        return ret;
@@ -1416,6 +1549,16 @@ int main(int argc, char **argv)
                        fmt.size_num = 2;
                        fmt.size_den = 1;
                        break;
+               case AV_PIX_FMT_YUVJ420P:
+                       fmt.fourcc = V4L2_PIX_FMT_YUV420M;
+                       fmt.size_num = 1;
+                       fmt.size_den = 1;
+                       break;
+               case AV_PIX_FMT_YUVJ422P:
+                       fmt.fourcc = V4L2_PIX_FMT_YUV422M;
+                       fmt.size_num = 1;
+                       fmt.size_den = 1;
+                       break;
                default:
                        printf("Invalid pixel format detected\n");
                        return -1;