Skip to content

Instantly share code, notes, and snippets.

@royshil
Created January 14, 2016 20:29
Show Gist options
  • Save royshil/fa98604b01787172b270 to your computer and use it in GitHub Desktop.
Save royshil/fa98604b01787172b270 to your computer and use it in GitHub Desktop.
Example of converting a YUYV buffer to JPEG using libJPEG
#include <iostream>
#include <fstream>
#include <vector>
#include <cstdint>
#include <memory>
#include <jpeglib.h>
using namespace std;
/**
* converts a YUYV raw buffer to a JPEG buffer.
* input is in YUYV (YUV 422). output is JPEG binary.
* from https://linuxtv.org/downloads/v4l-dvb-apis/V4L2-PIX-FMT-YUYV.html:
* Each four bytes is two pixels.
* Each four bytes is two Y's, a Cb and a Cr.
* Each Y goes to one of the pixels, and the Cb and Cr belong to both pixels.
*
* inspired by: http://stackoverflow.com/questions/17029136/weird-image-while-trying-to-compress-yuv-image-to-jpeg-using-libjpeg
*/
void compressYUYVtoJPEG(const vector<uint8_t>& input, const int width, const int height, vector<uint8_t>& output) {
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
JSAMPROW row_ptr[1];
int row_stride;
uint8_t* outbuffer = NULL;
uint64_t outlen = 0;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_mem_dest(&cinfo, &outbuffer, &outlen);
// jrow is a libjpeg row of samples array of 1 row pointer
cinfo.image_width = width & -1;
cinfo.image_height = height & -1;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_YCbCr; //libJPEG expects YUV 3bytes, 24bit
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, 92, TRUE);
jpeg_start_compress(&cinfo, TRUE);
vector<uint8_t> tmprowbuf(width * 3);
JSAMPROW row_pointer[1];
row_pointer[0] = &tmprowbuf[0];
while (cinfo.next_scanline < cinfo.image_height) {
unsigned i, j;
unsigned offset = cinfo.next_scanline * cinfo.image_width * 2; //offset to the correct row
for (i = 0, j = 0; i < cinfo.image_width * 2; i += 4, j += 6) { //input strides by 4 bytes, output strides by 6 (2 pixels)
tmprowbuf[j + 0] = input[offset + i + 0]; // Y (unique to this pixel)
tmprowbuf[j + 1] = input[offset + i + 1]; // U (shared between pixels)
tmprowbuf[j + 2] = input[offset + i + 3]; // V (shared between pixels)
tmprowbuf[j + 3] = input[offset + i + 2]; // Y (unique to this pixel)
tmprowbuf[j + 4] = input[offset + i + 1]; // U (shared between pixels)
tmprowbuf[j + 5] = input[offset + i + 3]; // V (shared between pixels)
}
jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
cout << "libjpeg produced " << outlen << " bytes" << endl;
output = vector<uint8_t>(outbuffer, outbuffer + outlen);
}
int main() {
ifstream input("frame-3.raw", ios::binary);
// copies all data into buffer
vector <uint8_t> inbuf((istreambuf_iterator<char>(input)), (istreambuf_iterator<char>()));
cout << "read " << inbuf.size() << " bytes" << endl;
vector<uint8_t> output;
compressYUYVtoJPEG(inbuf, 640, 480, output);
ofstream ofs("output.jpg", ios_base::binary);
ofs.write((const char*) &output[0], output.size());
ofs.close();
return 1;
}
@royshil
Copy link
Author

royshil commented Jan 14, 2016

@advanpix
Copy link

advanpix commented Jan 9, 2018

The "outbuffer" should be de-allocated with "free" at the end of compressYUYVtoJPEG

@heaveninfosoft
Copy link

UVCCamera.nativeStereoI420FrameBuffer any method like that???

public static final native void nativeStereoI420FrameBuffer(byte[] bArr, ByteBuffer byteBuffer, byte[] bArr2, int i, int i2);????????

@ilqvya
Copy link

ilqvya commented Feb 5, 2024

What the heck is the (width & -1) ? What is it ?

@royshil
Copy link
Author

royshil commented Feb 5, 2024

What the heck is the (width & -1) ? What is it ?

@effolkronium -1 would be a binary mask for a signed integer e.g. 0xFFFFFFFF
and & is a binray AND operator. so effectively it would mask the width with the integer making sure it doesn't overflow or get clipped

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment