libjpeg-turbo segmentation fault when writing scanlines to file c++ - c++

I have the following code running on windows 10 in QT Creator, I am trying to write rgb formatted data to a jpeg file using the libjpeg-turbo library
#include <stdio.h>
#include <jpeglib.h>
void writeJpeg(const char *filename, std::vector<unsigned char> &image, uint w, uint h) {
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *outfile;
JSAMPROW row_pointer[1];
int row_stride;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
if ((outfile = fopen(filename, "wb")) == NULL) {
fprintf(stderr, "can't open %s\n", filename);
exit(1);
}
jpeg_stdio_dest(&cinfo, outfile);
cinfo.image_width = w;
cinfo.image_height = h;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, 100, true);
jpeg_start_compress(&cinfo, true);
row_stride = w * 3;
JSAMPLE *arr = image.data();
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer[0] = &arr[cinfo.next_scanline * row_stride];
(void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_compress(&cinfo);
fclose(outfile);
jpeg_destroy_compress(&cinfo);
}
and get SIGSEGV on (void)jpeg_write_scanlines(&cinfo, row_pointer, 1); in this portion of the code
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer[0] = &arr[cinfo.next_scanline * row_stride];
(void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
I have tried debugging, but im not entirely sure what the best way to do that is.
I have found out that it crashes after 15 iterations of the loop and my best guess is that I have converted the data poorly from the vector into the pointer array.
Anyways, I cannot figure out how to better allocate the memory or if this is even the problem
Any ideas on what I'm doing wrong plus any tips on how to actually debug this in the future would be greatly appreciated.
EDIT
I changed true to TRUE and printed out every byte in the array like so
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer[0] = &arr[cinfo.next_scanline * row_stride];
QString out = "";
for (int i = 0; i<row_stride; i++)
out += QString::number(row_pointer[0][i]) + " ";
qDebug() << "\n\n==============" << cinfo.next_scanline << "==============\n\n";
qDebug() << out;
(void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
and after stepping through its execution, it is able to output all the bytes, yet still crashes on write_jpeg_scanlines
I also noticed some random text being printed out at the end of each scanline
ex:
255 255 255 25520003200!-�U3 on row 12
255 255 255 255eencoded�/�Rf on row 13
231 230 230 255,autoder�)�Pu on row 15, the data where it crashes
not sure if this is just garbage at the end of the pointer, or a symptom of qDebug but it could confirm antons idea of corrupted image data

I see nothing wrong in your code, except C++ bool value true is passed instead of C value TRUE in these calls:
jpeg_set_quality(&cinfo, 100, true);
...
jpeg_start_compress(&cinfo, true);
It may lead to weird crashes sometimes.
Also, the first thing I would try in this case - what if just to output somewhere all the bytes of every row arr[cinfo.next_scanline * row_stride] - does it crash? If it does, possibly you have error in other code preparing the image data.
UPD.: most probably the problem with original code was #include <jpeglib.h> - that should force to search for jpeglib.h in system directories instead of the libjpeg-turbo directories. That could be solved by using #include "jpeglib.h" and specifying the path to libjpeg-turbo include directory to compiler.

Thanks for all of the help, As #AntonMalyshev pointed out, the issue was an incorrect use of libjpeg.
First off I have libjpeg-turbo installed and while it includes a library for libjpeg im sure a better practice would be to just install libjpeg directly. I ended up using #include <turbojpeg.h>.
Secondly, the example code I posted, seems to be only compatible with base libjpeg Using this post and the libjpeg-turbo api I was able to come up with a solution that works.
Thanks, Ethan

Related

Segmentation fault while avcodec_encode_video2

I have some problems while trying to encode a AVFrame to a packet.
Before reading the whole code, the input stuff is working, I tested it. The output stuff is from an example here. I think there is the problem. But the segmentation fault occurs in the loop near the end.
Here is my reduced code:
void nmain() {
// input stuff
AVFormatContext *formatCtxIn=0;
AVInputFormat *formatIn=0;
AVCodecContext *codecCtxIn=0;
AVCodec *codecIn;
AVPacket *pktIn;
av_register_all();
avdevice_register_all();
avcodec_register_all();
formatIn = av_find_input_format("dshow");
if(!formatIn)
return;
AVDictionary *avoption=0;
av_dict_set(&avoption, "rtbufsize", "1000000000", NULL);
if(avformat_open_input(&formatCtxIn, "video=Integrated Camera", formatIn, &avoption)!=0)
return;
if(avformat_find_stream_info(formatCtxIn, NULL)<0)
return;
codecCtxIn = formatCtxIn->streams[0]->codec;
codecIn = avcodec_find_decoder(codecCtxIn->codec_id);
if(avcodec_open2(codecCtxIn, codecIn, NULL)<0)
return;
// end input stuff
//------------------------------------------------------------------------------
// output stuff
AVOutputFormat *formatOut=0;
AVFormatContext *formatCtxOut=0;
AVStream *streamOut=0;
AVFrame *frame=0;
AVCodec *codecOut=0;
AVPacket *pktOut;
const char *filename = "test.mpeg";
formatOut = av_guess_format(NULL, filename, NULL);
if(!formatOut)
formatOut = av_guess_format("mpeg", NULL, NULL);
if(!formatOut)
return;
formatCtxOut = avformat_alloc_context();
if(!formatCtxOut)
return;
formatCtxOut->oformat = formatOut;
sprintf(formatCtxOut->filename, "%s", filename);
if(formatOut->video_codec != AV_CODEC_ID_NONE) {
AVCodecContext *ctx;
codecOut = avcodec_find_encoder(formatOut->video_codec);
if(!codecOut)
return;
streamOut = avformat_new_stream(formatCtxOut, codecOut);
if(!streamOut)
return;
ctx = streamOut->codec;
ctx->bit_rate = 400000;
ctx->width = 352;
ctx->height = 288;
ctx->time_base.den = 25;
ctx->time_base.num = 1;
ctx->gop_size = 12;
ctx->pix_fmt = AV_PIX_FMT_YUV420P;
if(ctx->codec_id == AV_CODEC_ID_MPEG2VIDEO)
ctx->max_b_frames = 2;
if(ctx->codec_id == AV_CODEC_ID_MPEG1VIDEO)
ctx->mb_decision = 2;
if(formatCtxOut->oformat->flags & AVFMT_GLOBALHEADER)
ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
if(streamOut) {
AVCodecContext *ctx;
ctx = streamOut->codec;
if(avcodec_open2(ctx, codecOut, NULL) < 0)
return;
}
if(!(formatCtxOut->flags & AVFMT_NOFILE))
if(avio_open(&formatCtxOut->pb, filename, AVIO_FLAG_WRITE) < 0)
return;
avformat_write_header(formatCtxOut, NULL);
// doit
pktIn = new AVPacket;
pktOut = new AVPacket;
av_init_packet(pktOut);
pktOut->data = 0;
frame = avcodec_alloc_frame();
if(!frame)
return;
for(;;) {
if(av_read_frame(formatCtxIn, pktIn) >= 0) {
av_dup_packet(pktIn);
int fff;
if(avcodec_decode_video2(codecCtxIn, frame, &fff, pktIn) < 0)
std::cout << "bad frame" << std::endl;
if(!fff)
return; // ok
static int counter=0;
SaveFrame(frame, codecCtxIn->width, codecCtxIn->height, counter++); // work fine
// here a segmentation fault is occured.
if(avcodec_encode_video2(streamOut->codec, pktOut, frame, &fff) < 0)
std::cout << "bad frame" << std::endl;
}
}
}
// only for testing
// add to ensure frame is valid
void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) {
FILE *pFile;
char szFilename[32];
int y;
// Open file
sprintf(szFilename, "frame%d.ppm", iFrame);
pFile=fopen(szFilename, "wb");
if(pFile==NULL)
return;
// Write header
fprintf(pFile, "P6\n%d %d\n255\n", width, height);
// Write pixel data
for(y=0; y<height; y++)
fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);
// Close file
fclose(pFile);
}
What am i doing wrong?
While debugging i didn't found any problems with the parameters. streamOut->codec is filled. pktOut is allocated and frame is filled with the picture encoded before.
I think the problem is while creating the output codec but watching the example and looking to the doxypages it seems to be correct.
The trace route is from QT using msvc11 and framework 5.
I also tried to run with dr. memory and get this:
Error #26: UNADDRESSABLE ACCESS: reading 0x00000000-0x00000004 4 byte(s)
# 0 replace_memcpy [d:\derek\drmemory\withwiki\trunk\drmemory\replace.c:203]
# 1 avcodec-54.dll!ff_dct_quantize_c +0xd463 (0x6a482364 <avcodec-54.dll+0x3c2364>)
# 2 avcodec-54.dll!avcodec_encode_video2+0xb7 (0x6a56a5b8 <avcodec-54.dll+0x4aa5b8>)
# 3 nmain [d:\prg\tests\recording system-qt\libav\recsys\main.cpp:610]
# 4 main [d:\prg\tests\recording system-qt\libav\recsys\main.cpp:182]
Note: #0:00:06.318 in thread 5312
Note: instruction: mov (%edx) -> %ebx
It seems like the reading process while memcpy is going wrong.
Version:
I've forgot to mention the version of libav/ffmpeg i'm using:
libavutil 51. 76.100 / 51. 76.100
libavcodec 54. 67.100 / 54. 67.100
libavformat 54. 33.100 / 54. 33.100
libavdevice 54. 3.100 / 54. 3.100
libavfilter 3. 19.103 / 3. 19.103
libswscale 2. 1.101 / 2. 1.101
libswresample 0. 16.100 / 0. 16.100
libpostproc 52. 1.100 / 52. 1.100
Addendum:
Function SafeFrame is copied from tutorial 1.
Finally i solved my problem.
The problem is (apart from the documentation of libav) avpacket is not a (real) copy of the picture in the packet. it just points to the data of the packet. You have to make a copy, or better you have to let it libav do.
So first i created a new avframe for the output and a buffer on which the output avframe is pointing to.
AVFrame *outpic = avcodec_alloc_frame();
nbytes = avpicture_get_size(codecCtxOut->pix_fmt, codecCtxOut->width, codecCtxOut->height);
uint8_t* outbuffer = (uint8_t*)av_malloc(nbytes);
This buffer is used for the conversion from input to output. Then in the loop i have to fillup the outpic (avframe) with the buffer.
I have found in the code that this function is filling up the plane pointers with the buffer.
see here
avpicture_fill((AVPicture*)outpic, outbuffer, AV_PIX_FMT_YUV420P, codecCtxOut->width, codecCtxOut->height);
Then i converted the inpic to outpic using sws_scale. But first you have to setup the swscontext.
SwsContext* swsCtx_ = sws_getContext(codecCtxIn->width, codecCtxIn->height,
codecCtxIn->pix_fmt,
codecCtxOut->width, codecCtxOut->height,
codecCtxOut->pix_fmt,
SWS_BICUBIC, NULL, NULL, NULL);
sws_scale(swsCtx_, inpic->data, inpic->linesize, 0, codecCtxIn->height, outpic->data, outpic->linesize);
Then you can encode the outpic into pktout (avpacket for output). But first do free the output packet, otherwise you will get an error and a leak... see here
av_free_packet(pktOut);
if(avcodec_encode_video2(streamOut->codec, pktOut, outpic, &fff) < 0) {
std::cout << "shit frame" << std::endl;
continue;
}
// and write it to the file
formatOut->write_packet(formatCtxOut, pktOut);
So now it works (nearly fine) for me. Still a small memory leak, but this i can spot later.
I see at least two problems with that transcoding loop:
1) You're not checking whether the decoder produced a frame. Many decoders have a delay between input and output, so a decode call won't necessarily produce a frame even if no error occurs. You just have to keep passing packets to the decoder until it starts returning frames (and then flush it with NULL packets at the end, as described in the documentation).
The result is that you're passing an uninitialized frame to the encoder, which is probably the reason for the crash.
2) Another problem I see is that you're initing the ouput packet only once. As the documentation says
The user can supply an output buffer by setting avpkt->data and avpkt->size prior to calling the function, but if the size of the user-provided data is not large enough, encoding will fail. All other AVPacket fields will be reset by the encoder using av_init_packet(). If avpkt->data is NULL, the encoder will allocate it. The encoder will set avpkt->size to the size of the output packet. The returned data (if any) belongs to the caller, he is responsible for freeing it.
So if you only initialize it once before starting the transcode loop, on each iteration after the first it will contain the old data. The encoder will think you want to use that buffer for encoding and overwrite it. This will end in tears if you've already passed that packet to a muxer or something like that. So make sure to init packet data and size to NULL/0 before each encode call.

How do I get the DC coefficient from a jpg using the jpg library?

I am new to this stuff, but I need to get the dc-coefficient from a jpeg using the jpeg library?
I was told as a hint that the corresponding function is in jdhuff.c, but I can't find it. I tried to find a decent article about the jpg library where I can get this, but no success so far.
So I hope you guys can help me a bit and point me to either some documentation or have a hint.
So, here is what I know:
A jpg picture consists of 8x8 Blocks. That are 64 Pixels. 63 of it are named AC and 1 is named DC. Thats the coefficient. The position is at array[0][0].
But how do I exactly read that with the jpg library? I am using C++.
edit:
This is what I have so far:
read_jpeg::read_jpeg( const std::string& filename )
{
FILE* fp = NULL; // File-Pointer
jpeg_decompress_struct cinfo; // jpeg decompression parameters
JSAMPARRAY buffer; // Output row-buffer
int row_stride = 0; // physical row width
my_error_mgr jerr; // Custom Error Manager
// Set Error Manager
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
// Handle longjump
if (setjmp(jerr.setjmp_buffer)) {
// JPEG has signaled an error. Clean up and throw an exception.
jpeg_destroy_decompress(&cinfo);
fclose(fp);
throw std::runtime_error("Error: jpeg has reported an error.");
}
// Open the file
if ( (fp = fopen(filename.c_str(), "rb")) == NULL )
{
std::stringstream ss;
ss << "Error: Cannot read '" << filename.c_str() << "' from the specified location!";
throw std::runtime_error(ss.str());
}
// Initialize jpeg decompression
jpeg_create_decompress(&cinfo);
// Show jpeg where to read the data
jpeg_stdio_src(&cinfo, fp);
// Read the header
jpeg_read_header(&cinfo, TRUE);
// Decompress the file
jpeg_start_decompress(&cinfo);
// JSAMPLEs per row in output buffer
row_stride = cinfo.output_width * cinfo.output_components;
// Make a one-row-high sample array
buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
// Read image using jpgs counter
while (cinfo.output_scanline < cinfo.output_height)
{
// Read the image
jpeg_read_scanlines(&cinfo, buffer, 1);
}
// Finish the decompress
jpeg_finish_decompress(&cinfo);
// Release memory
jpeg_destroy_decompress(&cinfo);
// Close the file
fclose(fp);
}
This is not possible using the standard API. With libjpeg API the closest you can get is raw pixel data of Y/Cb/Cr channels.
To get coefficients' data you'd need to hack the decode_mcu function (or its callers) to save the data decoded there.

Debug Assertion Failed

Using Visual Studio 2010, C++.
Programming level: beginner.
I have a code from a book Windows Game Programming Gurus and up until now have managed all problems i have stumbled upon.
But this i don't know what it is.
Here is a screenshot of an error:
That is one nice 8-bit image...
Now, it says File: f:\dd...
In my case f: drive is empty cd-rom...
This is the line where i think error is happening:
_lseek(file_handle, -((int) (bitmap->bitmapinfoheader.biSizeImage)), SEEK_END);
What is this thing?
The f:\dd directory is where the source code of the "C Runtime Library" (CRT) was located, when it was built. Since Microsoft built that, it doesn't correspond to your F: drive.
Anyway, the CRT detected that one of the file handles is wrong. You passed it to the CRT, so you should check why it's wrong. If you press Retry, you'll be put in the debugger. There you can see which of your functions put in the wrong file handle.
It won't tell you why the handle is wrong, though. A common reason is that you tried to open a file, and forgot to check if it succeeded. You only get a file handle if the file name is valid, and you're allowed to read that file.
The assertion happens in the C library. It makes sure you pass valid argument to the lseek() function.
You probably did not check for errors after doing open() or creat() on the file.
Looks like your file_handle is wrong. Are you sure the opening of your image succeeded ?
Full function code which uses C++ ifstream instead of low-level IO functions.
Jonathan and i tried to make _lseek work only to conclude that it doesn't work...
Don't know if that is entirely true, maybe there is some way it works correctly.
If you (the reader) know, feel free to message me.
The function now works, although main program displays image wrongly, but that is beside matter of this question, _lseek thing is solved :)
int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename)
{
int file_handle = 0; // the file handle
int index = 0; // looping index
int bitmapWidth = 0;
int bitmapHeight = 0;
int bitmapSize = 0;
UCHAR *temp_buffer = NULL; // used to convert 24 bit images to 16 bit
streampos pos_cur;
ifstream bitmapFile = ifstream ();
bitmapFile.open (filename, ifstream::in);
if (! bitmapFile.is_open ())
{
printError ("Error: OpenFile function failure. ");
// abort
return(0);
}
// load the bitmap file header:
//_lread(file_handle, &(bitmap->bitmapfileheader), sizeof(BITMAPFILEHEADER));
bitmapFile.read ((char *) &(bitmap->bitmapfileheader), sizeof (BITMAPFILEHEADER));
// test if this is a bitmap file
if (bitmap->bitmapfileheader.bfType != BITMAP_ID)
{
// close the file
//_lclose(file_handle);
bitmapFile.close ();
printError ("error: wrong bitmap type");
cout << "error: wrong bitmap type" << endl;
// return error
return(0);
} // end if
// now we know this is a bitmap, so read in all the sections.
if (bitmap->bitmapinfoheader.biSizeImage == 0)
printError ("error: biSizeImage equals 0");
// now the bitmap infoheader:
//_lread(file_handle, &bitmap->bitmapinfoheader, sizeof(BITMAPINFOHEADER));
bitmapFile.seekg (sizeof (BITMAPFILEHEADER), ios::beg);
pos_cur = bitmapFile.tellg (); // save current stream position
bitmapFile.read ((char *) &(bitmap->bitmapinfoheader), sizeof (BITMAPINFOHEADER));
//cout << bitmap->bitmapinfoheader.biBitCount << endl;
// now load the color palette if there is one
if (bitmap->bitmapinfoheader.biBitCount == 8)
{
//_lread(file_handle, &bitmap->palette, MAX_COLORS_PALETTE * sizeof(PALETTEENTRY));
// not tested:
bitmapFile.read ((char *) &(bitmap->palette), MAX_COLORS_PALETTE * sizeof(PALETTEENTRY));
// now set all the flags in the palette correctly and fix the reversed
// BGR RGBQUAD data format
for (index = 0; index < MAX_COLORS_PALETTE; index++)
{
// reverse the red and green fields
int temp_color = bitmap->palette[index].peRed;
bitmap->palette[index].peRed = bitmap->palette[index].peBlue;
bitmap->palette[index].peBlue = temp_color;
// always set the flags word to this
bitmap->palette[index].peFlags = PC_NOCOLLAPSE;
} // end for index
} // end if
bitmapWidth = bitmap->bitmapinfoheader.biWidth * (bitmap->bitmapinfoheader.biBitCount / 8);
bitmapHeight = bitmap->bitmapinfoheader.biHeight;
bitmapSize = bitmapWidth * bitmapHeight;
// finally the image data itself:
//_lseek(file_handle, -((int) (bitmap->bitmapinfoheader.biSizeImage)), SEEK_END);
bitmapFile.seekg (-((int) bitmapSize), ios::end);
//bitmapFile.seekg (sizeof (BITMAPINFOHEADER) + sizeof (BITMAPFILEHEADER) + MAX_COLORS_PALETTE * sizeof(PALETTEENTRY), ios::beg);
// now read in the image, if the image is 8 or 16 bit then simply read it
// but if its 24 bit then read it into a temporary area and then convert
// it to a 16 bit image
if (bitmap->bitmapinfoheader.biBitCount == 8 ||
bitmap->bitmapinfoheader.biBitCount == 16 ||
bitmap->bitmapinfoheader.biBitCount == 24)
{
// delete the last image if there was one
if (bitmap->buffer)
free(bitmap->buffer);
// allocate the memory for the image
//if (!(bitmap->buffer = (UCHAR *) malloc (bitmap->bitmapinfoheader.biSizeImage))) // error: biSizeImage == 0 !
if (!(bitmap->buffer = (UCHAR *) malloc (bitmapSize)))
{
// close the file
//_lclose(file_handle);
bitmapFile.close ();
// return error
return(0);
} // end if
// now read it in
//_lread(file_handle, bitmap->buffer, bitmap->bitmapinfoheader.biSizeImage);
bitmapFile.read ((char *) (bitmap->buffer), bitmapSize);
} // end if
else
{
// serious problem
return(0);
} // end else
// close the file
//_lclose(file_handle);
bitmapFile.close ();
// flip the bitmap
Flip_Bitmap(bitmap->buffer,
bitmap->bitmapinfoheader.biWidth * (bitmap->bitmapinfoheader.biBitCount / 8),
bitmap->bitmapinfoheader.biHeight);
//cout << "biSizeImage: " << bitmap->bitmapinfoheader.biSizeImage << endl;
//cout << (bitmap->bitmapinfoheader.biWidth * (bitmap->bitmapinfoheader.biBitCount / 8)) * bitmap->bitmapinfoheader.biHeight << endl;
// return success
return(1);
} // end Load_Bitmap_File
///////////////////////////////////////////////////////////
Current full source code:
http://pastebin.com/QQ6fMD7P
Expiration date is set to never.
Thanks to all people contributing to this question!
lseek crashes with the debug assertion failed error because it is a 16bit function. I found this out by looking at a chart of 16bit and 32bit functions on the microsoft website.
Solution is to use _llseek. _llseek is a 32bit function and can run on 64bit computers.
You do not need to change any parameters from _lseek to use _llseek.
_lseek(file_handle, -((int) (bitmap->bitmapinfoheader.biSizeImage)), SEEK_END);
becomes
_llseek(file_handle, -((int) (bitmap->bitmapinfoheader.biSizeImage)), SEEK_END);

Write to memory buffer instead of file with libjpeg?

I have found this function which uses libjpeg to write to a file:
int write_jpeg_file( char *filename )
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
/* this is a pointer to one row of image data */
JSAMPROW row_pointer[1];
FILE *outfile = fopen( filename, "wb" );
if ( !outfile )
{
printf("Error opening output jpeg file %s\n!", filename );
return -1;
}
cinfo.err = jpeg_std_error( &jerr );
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, outfile);
/* Setting the parameters of the output file here */
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.input_components = bytes_per_pixel;
cinfo.in_color_space = color_space;
/* default compression parameters, we shouldn't be worried about these */
jpeg_set_defaults( &cinfo );
/* Now do the compression .. */
jpeg_start_compress( &cinfo, TRUE );
/* like reading a file, this time write one row at a time */
while( cinfo.next_scanline < cinfo.image_height )
{
row_pointer[0] = &raw_image[ cinfo.next_scanline * cinfo.image_width * cinfo.input_components];
jpeg_write_scanlines( &cinfo, row_pointer, 1 );
}
/* similar to read file, clean up after we're done compressing */
jpeg_finish_compress( &cinfo );
jpeg_destroy_compress( &cinfo );
fclose( outfile );
/* success code is 1! */
return 1;
}
I would actually need to write the jpeg compressed image just to memory buffer, without saving it to a file, to save time. Could somebody give me an example how to do it?
I have been searching the web for a while but the documentation is very rare if any and examples are also difficult to come by.
You can define your own destination manager quite easily. The jpeg_compress_struct contains a pointer to a jpeg_destination_mgr, which contains a pointer to a buffer, a count of space left in the buffer, and 3 pointers to functions:
init_destination (j_compress_ptr cinfo)
empty_output_buffer (j_compress_ptr cinfo)
term_destination (j_compress_ptr cinfo)
You need to fill in the function pointers before you make the first call into the jpeg library, and let those functions handle the buffer. If you create a buffer that is larger than the largest possible output that you expect, this becomes trivial; init_destination just fills in the buffer pointer and count, and empty_output_buffer and term_destination do nothing.
Here's some sample code:
std::vector<JOCTET> my_buffer;
#define BLOCK_SIZE 16384
void my_init_destination(j_compress_ptr cinfo)
{
my_buffer.resize(BLOCK_SIZE);
cinfo->dest->next_output_byte = &my_buffer[0];
cinfo->dest->free_in_buffer = my_buffer.size();
}
boolean my_empty_output_buffer(j_compress_ptr cinfo)
{
size_t oldsize = my_buffer.size();
my_buffer.resize(oldsize + BLOCK_SIZE);
cinfo->dest->next_output_byte = &my_buffer[oldsize];
cinfo->dest->free_in_buffer = my_buffer.size() - oldsize;
return true;
}
void my_term_destination(j_compress_ptr cinfo)
{
my_buffer.resize(my_buffer.size() - cinfo->dest->free_in_buffer);
}
cinfo->dest->init_destination = &my_init_destination;
cinfo->dest->empty_output_buffer = &my_empty_output_buffer;
cinfo->dest->term_destination = &my_term_destination;
There is a predefined function jpeg_mem_src defined in jdatasrc.c. The simplest usage example:
unsigned char *mem = NULL;
unsigned long mem_size = 0;
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_mem_dest(&cinfo, &mem, &mem_size);
// do compression
// use mem buffer
Do not forget to deallocate your buffer.
I have tried Mark's solution and on my platform it always gives SEGMENTATION FALUT error when it executes
cinfo->dest->term_destination = &my_term_destination;
And I turned to the jpeglib source codes (jdatadst.c) and found this:
jpeg_mem_dest (j_compress_ptr cinfo, unsigned char ** outbuffer, unsigned long * outsize)
just below the method jpeg_stdio_dest(), and I've tried it by simply fill in the address of the buffer(char*) and the address of the buffer size(int). The destination manager automatically allocates memory for the buffer and the program need to free the memory after use.
It successfully runs on my platform, Beaglebone Black with the pre-installed Angstrom Linux. My libjpeg version is 8d.
All you need to do is pass a FILE-like object to jpeg_stdio_dest().
unsigned char ***image_ptr
unsigned char* ptr;
unsigned char** image_buf;
for(int i=0;i<h;i++){
image_buf[i] = new unsigned char[w*o];
}
ptr = image_buf[0];
while (info.output_scanline < info.image_height) {
jpeg_read_scanlines(&info,&ptr,1);
ptr = image_buf[c];
c++;
}
*image_ptr = image_buf;
This is all you need to read.
JSAMPROW row_pointer;
while (info.next_scanline < info.image_height) {
row_pointer = &image_buf[info.next_scanline][0];
(void) jpeg_write_scanlines(&info, &row_pointer, 1);
}
And this is all you need to write.

MEX-File to Output Pulse in a Loop to a DAQ-Board

i figured I must use a MEX-File to output Digital pulses in a loop (40 kHz) from Matlab to my DAQ-Board, I have some APIs from the DAQ-Board vendor, but I really dont know if they are useful.
It´s a big documentation on the Mathworks website about MEX-File and APIs, that just make me confused.
So I´m asking here if someone can orientate me or showing me an example Code to realise this!!
I wrote a small winsock package using mex functions a while back because Matlab's tcpip stuff was having issues with sending large amounts of data (like images). I don't know much about mex functions other than what I learned to get that package working, and even that was quite some time ago. But, here's some of my notes from before and one of the functions I wrote as an example that hopefully might be some help for you.
Before writing any mex functions, you need to configure Matlab to be able to compile them. You do this by typing "mex -setup" in the matlab command line and following the instructions it gives. I configured it to use the Visual Studio compiler (note that you have to have Visual Studio installed for this option to show up).
After configuring the compiler, you compile your mex functions by typing "mex filename.cpp" in the Matlab command-line. This produces a .mexw32 file (assuming 32-bit) that Matlab uses when you call your mex function.
To write the mex function itself, you write an m-file to declare it and provide comments as well as a cpp file with the actual implementation.
As an example, here's one of the m-files I wrote:
function sendColorImage( socketHandle, colorImage ) %#ok<*INUSD>
%SENDCOLORIMAGE Sends a color image over the given socket
% This function sends a color image over the socket provided. The image
% is really just an MxNx3 matrix. Note that this function sends the
% image data in the order in which Matlab stores it (non-interlaced
% column major order), which is different from most other languages.
% This means the red values for every pixel will be sent first, then the
% green values, then the blue values. Furthermore, the scanlines read
% from the top of the image to the bottom, starting at the left side of
% the image.
%
% socketHande - A handle to the socket over which the image should be
% sent. This handle is returned by the openSocket function when the
% socket is first created.
%
% colorImage - An MxNx3 matrix containing the image data. This matrix
% should be in the same format as a matrix loaded using Matlabs imread
% function.
%
% This is a mex function and is defined in its corresponding .cpp file.
And here's the corresponding cpp file. Note that I just made up my own message format and had corresponding C# code that parsed it back out of the byte stream.
// Instruct the compiler to link with wsock32.lib (in case it isn't specified on the command line)
#pragma comment(lib,"wsock32.lib")
#include "mex.h"
#include <winsock2.h>
#include <cstdio>
#include "protocol.h"
// See the corresponding .m file for documentation on this mex function.
void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]){
char errorMessage[100];
// Validate input and output arguments
if(nlhs != 0)
mexErrMsgTxt("There are no output arguments for this function.");
if(nrhs != 2)
mexErrMsgTxt("Must have 2 input parameters: the socket handle and the MxNx3 image matrix");
if(!mxIsClass(prhs[0], "uint32"))
mexErrMsgTxt("The first input parameter should be a uint32 containing the socket handle");
if(!mxIsClass(prhs[1], "uint8") || mxGetNumberOfDimensions(prhs[1]) != 3 || mxGetDimensions(prhs[1])[2] != 3)
mexErrMsgTxt("The 2nd input parameter should be an MxNx3 uint8 matrix containing the image");
// Get the socket handle
SOCKET socketHandle = (int)(mxGetPr(prhs[0])[0]);
// Set up the header
int frameWidth = mxGetDimensions(prhs[1])[1];
int frameHeight = mxGetDimensions(prhs[1])[0];
int header[3];
header[0] = COLOR_IMAGE;
header[1] = frameWidth;
header[2] = frameHeight;
// Send the header
int bytesSent;
int totalBytesSent = 0;
while(totalBytesSent < 3*sizeof(int)){
bytesSent = send(socketHandle, ((char*)header) + totalBytesSent, 3*sizeof(int) - totalBytesSent, 0);
if(bytesSent == SOCKET_ERROR){
sprintf(errorMessage, "Error sending image header over the socket: %d", WSAGetLastError());
mexErrMsgTxt(errorMessage);
}
totalBytesSent += bytesSent;
}
// Send the image
totalBytesSent = 0;
int totalBytesToSend = frameWidth * frameHeight * 3;
char* dataPointer = (char*)mxGetData(prhs[1]);
while(totalBytesSent < totalBytesToSend){
bytesSent = send(socketHandle, dataPointer + totalBytesSent, totalBytesToSend - totalBytesSent, 0);
if(bytesSent == SOCKET_ERROR){
sprintf(errorMessage, "Error sending image over the socket: %d", WSAGetLastError());
mexErrMsgTxt(errorMessage);
}
totalBytesSent += bytesSent;
}
}