Because some cameras currently collect yuyv images and cannot convert them into JPEG image formats by themselves, it is quite troublesome for us to watch .. Therefore, the source code of MJPEG-streamer is referenced.
The conversion function is obtained from this function. You can convert the format of yuyv to JPEG through your own combination, so that we can implement remote monitoring through the network. The source code is as follows:
// The code is complicated and not organized ..
# Include <stdio. h>
# Include <stdlib. h>
# Include <string. h>
# Include <assert. h>
# Include <getopt. h>
# Include <fcntl. h>
# Include <unistd. h>
# Include <errno. h>
# Include <malloc. h>
# Include <sys/STAT. h>
# Include <sys/types. h>
# Include <sys/time. h>
# Include <sys/Mman. h>
# Include <sys/IOCTL. h>
# Include <ASM/types. h>
# Include <Linux/videodev2.h>
# Include <cmdlib. h>
# Define output_buf_size 4096
# Define clear (x) memset (& (x), 0, sizeof (x ))
# Define width 320
# Define height 240
Struct buffer {
Void * start;
Size_t length;
};
Typedef struct {
Struct cmd_destination_mgr pub;
Joctet * buffer;
Unsigned char * outbuffer;
Int outbuffer_size;
Unsigned char * outbuffer_cursor;
Int * written;
} Mjpg_destination_mgr;
Typedef mjpg_destination_mgr * mjpg_dest_ptr;
Static char * dev_name = "/dev/video0 ";
Static int FD =-1;
Struct buffer * buffers = NULL;
Static unsigned int n_buffers = 0;
File * file_fd;
Static unsigned long file_length;
Static unsigned char * file_name;
Methoddef (void) init_destination (j_compress_ptr Cinfo ){
Mjpg_dest_ptr DEST = (mjpg_dest_ptr) Cinfo-> DEST;
DeST-> buffer = (joctet *) (* Cinfo-> mem-> alloc_small) (j_common_ptr) Cinfo, jpool_image, output_buf_size * sizeof (joctet ));
* (DEST-> written) = 0;
DeST-> pub. next_output_byte = DEST-> buffer;
DeST-> pub. free_in_buffer = output_buf_size;
}
Methoddef (Boolean) empty_output_buffer (j_compress_ptr Cinfo ){
Mjpg_dest_ptr DEST = (mjpg_dest_ptr) Cinfo-> DEST;
Memcpy (DEST-> outbuffer_cursor, DEST-> buffer, output_buf_size );
DeST-> outbuffer_cursor + = output_buf_size;
* (DEST-> written) + = output_buf_size;
DeST-> pub. next_output_byte = DEST-> buffer;
DeST-> pub. free_in_buffer = output_buf_size;
Return true;
}
Methoddef (void) term_destination (j_compress_ptr Cinfo ){
Mjpg_dest_ptr DEST = (mjpg_dest_ptr) Cinfo-> DEST;
Size_t datacount = output_buf_size-Dest-> pub. free_in_buffer;
/* Write any data remaining in the buffer */
Memcpy (DEST-> outbuffer_cursor, DEST-> buffer, datacount );
DeST-> outbuffer_cursor + = datacount;
* (DEST-> written) + = datacount;
}
Void dest_buffer (j_compress_ptr Cinfo, unsigned char * buffer, int size, int * written ){
Mjpg_dest_ptr DEST;
If (Cinfo-> DEST = NULL ){
Cinfo-> DEST = (struct cmd_destination_mgr *) (* Cinfo-> mem-> alloc_small) (j_common_ptr) Cinfo, jpool_permanent, sizeof (mjpg_destination_mgr ));
}
DeST = (mjpg_dest_ptr) Cinfo-> DEST;
DeST-> pub. init_destination = init_destination;
DeST-> pub. empty_output_buffer = empty_output_buffer;
DeST-> pub. term_destination = term_destination;
DeST-> outbuffer = buffer;
DeST-> outbuffer_size = size;
DeST-> outbuffer_cursor = buffer;
DeST-> written = written;
}
// Convert the yuyv format collected by the camera to JPEG format
Int compress_yuyv_to_jpeg (unsigned char * Buf, unsigned char * buffer, int size, int quality ){
Struct performance_compress_struct Cinfo;
Struct performance_error_mgr Jerr;
Jsamprow row_pointer [1];
Unsigned char * line_buffer, * yuyv;
Int Z;
Static int written;
// Int COUNT = 0;
// Printf ("% s \ n", Buf );
Line_buffer = calloc (width * 3, 1 );
Yuyv = Buf; // assign the image data in yuyv format to the yuyv pointer.
Printf ("compress start... \ n ");
Cinfo. Err = maid (& Jerr );
Pai_create_compress (& Cinfo );
/* Pai_stdio_dest (& Cinfo, file );*/
Dest_buffer (& Cinfo, buffer, size, & written );
Cinfo. image_width = width;
Cinfo. image_height = height;
Cinfo. input_components = 3;
Cinfo. in_color_space = jcs_rgb;
Pai_set_defaults (& Cinfo );
Performance_set_quality (& Cinfo, quality, true );
Performance_start_compress (& Cinfo, true );
Z = 0;
While (Cinfo. next_scanline
Int X;
Unsigned char * PTR = line_buffer;
For (x = 0; x <width; X ++ ){
Int R, G, B;
Int y, U, V;
If (! Z)
Y = yuyv [0] <8;
Else
Y = yuyv [2] <8;
U = yuyv [1]-128;
V = Yu YV [3]-128;
R = (Y + (359 * V)> 8;
G = (Y-(88 * u)-(183 x V)> 8;
B = (Y + (454 * u)> 8;
* (PTR ++) = (r> 255 )? 255: (r <0 )? 0: R );
* (PTR ++) = (G> 255 )? 255: (g <0 )? 0: G );
* (PTR ++) = (B> 255 )? 255: (B <0 )? 0: B );
If (Z ++ ){
Z = 0;
Yuyv + = 4;
}
}
Row_pointer [0] = line_buffer;
Pai_write_scanlines (& Cinfo, row_pointer, 1 );
}
Pai_finish_compress (& Cinfo );
Pai_destroy_compress (& Cinfo );
Free (line_buffer );
Return (written );
}
// Read the content of a frame
Static int read_frame (void)
{
Struct v4l2_buffer Buf;
Int ret;
Unsigned int I;
Clear (BUF );
Buf. type = v4l2_buf_type_video_capture;
Buf. Memory = v4l2_memory_mmap;
Int FF = IOCTL (FD, vidioc_dqbuf, & BUF); // buffer of frames collected from columns
If (FF <0)
Printf ("failture \ n ");
Unsigned char SRC [Buf. Length + 1];
Unsigned char Dest [Buf. Length + 1];
Assert (BUF. index <n_buffers );
Printf ("Buf. Index DQ is % d, \ n", Buf. Index );
Memcpy (SRC, buffers [Buf. Index]. Start, Buf. Length );
Ret = compress_yuyv_to_jpeg (SRC, DEST, (width * height), 80); // Data Conversion
Fwrite (DEST, RET, 1, file_fd); // write data after conversion
FF = IOCTL (FD, vidioc_qbuf, & BUF); // re-import the column
If (FF <0)
Printf ("failture vidioc_qbuf \ n ");
Return 1;
}
Int get_picture ()
{
Struct v4l2_capability cap;
Struct v4l2_format FMT;
Unsigned int I;
Enum v4l2_buf_type;
File_fd = fopen ("test-mmap.jpg", "W ");
FD = open (dev_name, o_rdwr | o_nonblock, 0 );
Int FF = IOCTL (FD, vidioc_querycap, & Cap); // obtain camera parameters
If (FF <0)
Printf ("failture vidioc_querycap \ n ");
Struct v4l2_fmtdesc fmt1;
Int ret;
Memset (& fmt1, 0, sizeof (fmt1 ));
Fmt1.index = 0;
Fmt1.type = v4l2_buf_type_video_capture;
While (ret = IOCTL (FD, vidioc_enum_fmt, & fmt1) = 0) // view the formats supported by the camera
{
Fmt1.index ++;
Printf ("{pixelformat = '% C % C', description =' % s'} \ n ",
Fmt1.pixelformat & 0xff, (fmt1.pixelformat> 8) & 0xff,
(Fmt1.pixelformat> 16) & 0xff, (fmt1.pixelformat> 24) & 0xff,
Fmt1.description );
}
Clear (FMT );
FMT. type = v4l2_buf_type_video_capture;
FMT. FMT. pix. width = 640;
FMT. FMT. pix. Height = 480;
FMT. FMT. pix. pixelformat = v4l2_pix_fmt_yuyv;
FMT. FMT. pix. Field = v4l2_field_interlaced;
FF = IOCTL (FD, vidioc_s_fmt, & FMT); // sets the image format
If (FF <0)
Printf ("failture vidioc_s_fmt \ n ");
File_length = FMT. FMT. pix. bytesperline * FMT. FMT. pix. height; // calculate the image size.
Struct v4l2_requestbuffers req;
Clear (req );
Req. Count = 1;
Req. type = v4l2_buf_type_video_capture;
Req. Memory = v4l2_memory_mmap;
IOCTL (FD, vidioc_reqbufs, & req); // Request Buffer. Count indicates the number of requests.
If (FF <0)
Printf ("failture vidioc_reqbufs \ n ");
If (req. Count <1)
Printf ("insufficient buffer memory \ n ");
Buffers = calloc (req. Count, sizeof (* buffers); // create the corresponding space in the memory
For (n_buffers = 0; n_buffers <Req. Count; ++ n_buffers)
{
Struct v4l2_buffer Buf;
Clear (BUF );
Buf. type = v4l2_buf_type_video_capture;
Buf. Memory = v4l2_memory_mmap;
Buf. Index = n_buffers;
If (-1 = IOCTL (FD, vidioc_querybuf, & BUF) // map the user space
Printf ("vidioc_querybuf error \ n ");
Buffers [n_buffers]. Length = Buf. length;
Buffers [n_buffers]. Start = MMAP (null, Buf. length, prot_read | prot_write, map_shared, FD, Buf. M. offset); // create a ing through MMAP
If (map_failed = buffers [n_buffers]. Start)
Printf ("MMAP failed \ n ");
}
For (I = 0; I <n_buffers; ++ I)
{
Struct v4l2_buffer Buf;
Clear (BUF );
Buf. type = v4l2_buf_type_video_capture;
Buf. Memory = v4l2_memory_mmap;
Buf. Index = I;
If (-1 = IOCTL (FD, vidioc_qbuf, & BUF) // The requested buffer enters the queue
Printf ("vidioc_qbuf failed \ n ");
}
Type = v4l2_buf_type_video_capture;
If (-1 = IOCTL (FD, vidioc_streamon, & type) // start capturing image data
Printf ("vidioc_streamon failed \ n ");
For (;) // This section involves asynchronous Io
{
Fd_set FDS;
Struct timeval TV;
Int R;
Fd_zero (& FDs); // clears the specified file descriptor set
Fd_set (FD, & FDs); // Add a new file descriptor to the file descriptor set.
/* Timeout .*/
TV. TV _sec = 2;
TV. TV _usec = 0;
R = select (FD + 1, & FDS, null, null, & TV); // determines whether the camera is readable (that is, whether the camera is ready), and TV is timed
If (-1 = r)
{
If (eintr = errno)
Continue;
Printf ("select err \ n ");
}
If (0 = r)
{
Fprintf (stderr, "select timeout \ n ");
Exit (exit_failure );
}
If (read_frame () // if it is readable, run the read_frame function.
Break;
}
Unmap:
For (I = 0; I <n_buffers; ++ I)
If (-1 = munmap (buffers [I]. Start, buffers [I]. Length ))
Printf ("munmap error ");
Type = v4l2_buf_type_video_capture;
If (-1 = IOCTL (FD, vidioc_streamoff, & type ))
Printf ("vidioc_streamoff ");
Close (FD );
Fclose (file_fd );
Exit (exit_success );
Return 0;
}