libjpeg custom source manager - c++

So I've been reading the libjpeg documentation and it is extremely lackluster.
I have been trying to figure out how to read from a custom memory buffer rather than a file and am not sure how to even test if my solution is working correctly.
At the moment my function for loading a jpeg from memory is like so:
struct error_mgr{
jpeg_error_mgr pub;
std::jmp_buf buf;
};
bool load_jpeg(void *mem, size_t size, output_struct &output){
jpeg_source_mgr src;
src.next_input_bytes = static_cast<JOCTET*>(mem)-size;
src.bytes_in_buffer = size;
src.init_source = [](j_compress_ptr){};
src.fill_input_buffer = [](j_decompress_ptr cinfo) -> boolean{
// should never reach end of buffer
throw "libjpeg tried to read past end of file";
return true;
};
src.skip_input_data = [](j_compress_ptr cinfo, long num_bytes){
if(num_bytes < 1) return; // negative or 0 us no-op
cinfo->src.next_input_byte+=num_bytes;
cinfo->src.bytes_in_buffer-=num_bytes;
};
src.resync_to_restart = jpeg_resync_to_restart;
src.term_source = [](j_decompress_ptr){};
struct jpeg_decompress_struct cinfo;
error_mgr err;
cinfo.err = jpeg_std_error(&err.pub);
err.pub.error_exit = [](j_common_ptr cinfo){
error_mgr ptr = reinterpret_cast<error_mgr*>(cinfo->err);
std::longjmp(ptr->buf, 1);
};
if(std::setjmp(err.buf)){
jpeg_destroy_decompress(&cinfo);
return false;
}
cinfo.src = &src;
jpeg_create_decompress(&cinfo);
(void) jpeg_read_header(&cinfo, TRUE);
// do the actual reading of the image
return true;
}
But it never makes it past jpeg_read_header.
I know that this is a jpeg file and I know that my memory is being passed correctly because I have libpng loading images with the same signature and calling function fine, so I'm sure it is how I am setting the source manager in cinfo.
Anybody with more experience in libjpeg know how to do this?

In my code I am setting cinfo.src before calling jpeg_create_decompress, setting it afterwards fixed the issue :)

Using jpeg_mem_src() works for me, with libjpeg-turbo:
struct jpeg_decompress_struct cinfo;
/* ... */
char *ptr;
size_t buffer;
/* Initialize ptr, buffer, then: */
jpeg_mem_src(&cinfo, ptr, buffer);
/* Now, it's time for jpeg_read_header(), etc... */

Related

ffmpeg(libavcodec). memory leaks in avcodec_encode_video

I'm trying to transcode a video with help of libavcodec.
On transcoding big video files(hour or more) i get huge memory leaks in avcodec_encode_video. I have tried to debug it, but with different video files different functions produce leaks, i have got a little bit confused about that :). Here FFMPEG with QT memory leak is the same issue that i have, but i have no idea how did that person solve it. QtFFmpegwrapper seems to do the same i do(or i missed something).
my method is lower. I took care about aFrame and aPacket outside with av_free and av_free_packet.
int
Videocut::encode(
AVStream *anOutputStream,
AVFrame *aFrame,
AVPacket *aPacket
)
{
AVCodecContext *outputCodec = anOutputStream->codec;
if (!anOutputStream ||
!aFrame ||
!aPacket)
{
return 1;
/* NOTREACHED */
}
uint8_t * buffer = (uint8_t *)malloc(
sizeof(uint8_t) * _DefaultEncodeBufferSize
);
if (NULL == buffer) {
return 2;
/* NOTREACHED */
}
int packetSize = avcodec_encode_video(
outputCodec,
buffer,
_DefaultEncodeBufferSize,
aFrame
);
if (packetSize < 0) {
free(buffer);
return 1;
/* NOTREACHED */
}
aPacket->data = buffer;
aPacket->size = packetSize;
return 0;
}
The first step would be to try to reproduce your problem under Valgrind on a Linux box, if you can.
ffmpeg encoders and decoders usually not dynamically allocate memory; they reuse buffers between calls. Leaks are usually going to be in the frames somewhere.
Note that av_free_packet will only free your dynamically allocated buffer if the packet has a destructor function!
Look at how the function is defined in libavcodec/avpacket.c:
void av_free_packet(AVPacket *pkt)
{
if (pkt) {
if (pkt->destruct) pkt->destruct(pkt);
pkt->data = NULL; pkt->size = 0;
pkt->side_data = NULL;
pkt->side_data_elems = 0;
}
}
If there is no pkt->destruct function, no clean up takes place!

Libzip - read file contents from zip

I using libzip to work with zip files and everything goes fine, until i need to read file from zip
I need to read just a whole text files, so it will be great to achieve something like PHP "file_get_contents" function.
To read file from zip there is a function "int
zip_fread(struct zip_file *file, void *buf, zip_uint64_t nbytes)".
Main problem what i don't know what size of buf must be and how many nbytes i must read (well i need to read whole file, but files have different size). I can just do a big buffer to fit them all and read all it's size, or do a while loop until fread return -1 but i don't think it's rational option.
You can try using zip_stat to get file size.
http://linux.die.net/man/3/zip_stat
I haven't used the libzip interface but from what you write it seems to look very similar to a file interface: once you got a handle to the stream you keep calling zip_fread() until this function return an error (ir, possibly, less than requested bytes). The buffer you pass in us just a reasonably size temporary buffer where the data is communicated.
Personally I would probably create a stream buffer for this so once the file in the zip archive is set up it can be read using the conventional I/O stream methods. This would look something like this:
struct zipbuf: std::streambuf {
zipbuf(???): file_(???) {}
private:
zip_file* file_;
enum { s_size = 8196 };
char buffer_[s_size];
int underflow() {
int rc(zip_fread(this->file_, this->buffer_, s_size));
this->setg(this->buffer_, this->buffer_,
this->buffer_ + std::max(0, rc));
return this->gptr() == this->egptr()
? traits_type::eof()
: traits_type::to_int_type(*this->gptr());
}
};
With this stream buffer you should be able to create an std::istream and read the file into whatever structure you need:
zipbuf buf(???);
std::istream in(&buf);
...
Obviously, this code isn't tested or compiled. However, when you replace the ??? with whatever is needed to open the zip file, I'd think this should pretty much work.
Here is a routine I wrote that extracts data from a zip-stream and prints out a line at a time. This uses zlib, not libzip, but if this code is useful to you, feel free to use it:
#
# compile with -lz option in order to link in the zlib library
#
#include <zlib.h>
#define Z_CHUNK 2097152
int unzipFile(const char *fName)
{
z_stream zStream;
char *zRemainderBuf = malloc(1);
unsigned char zInBuf[Z_CHUNK];
unsigned char zOutBuf[Z_CHUNK];
char zLineBuf[Z_CHUNK];
unsigned int zHave, zBufIdx, zBufOffset, zOutBufIdx;
int zError;
FILE *inFp = fopen(fName, "rbR");
if (!inFp) { fprintf(stderr, "could not open file: %s\n", fName); return EXIT_FAILURE; }
zStream.zalloc = Z_NULL;
zStream.zfree = Z_NULL;
zStream.opaque = Z_NULL;
zStream.avail_in = 0;
zStream.next_in = Z_NULL;
zError = inflateInit2(&zStream, (15+32)); /* cf. http://www.zlib.net/manual.html */
if (zError != Z_OK) { fprintf(stderr, "could not initialize z-stream\n"); return EXIT_FAILURE; }
*zRemainderBuf = '\0';
do {
zStream.avail_in = fread(zInBuf, 1, Z_CHUNK, inFp);
if (zStream.avail_in == 0)
break;
zStream.next_in = zInBuf;
do {
zStream.avail_out = Z_CHUNK;
zStream.next_out = zOutBuf;
zError = inflate(&zStream, Z_NO_FLUSH);
switch (zError) {
case Z_NEED_DICT: { fprintf(stderr, "Z-stream needs dictionary!\n"); return EXIT_FAILURE; }
case Z_DATA_ERROR: { fprintf(stderr, "Z-stream suffered data error!\n"); return EXIT_FAILURE; }
case Z_MEM_ERROR: { fprintf(stderr, "Z-stream suffered memory error!\n"); return EXIT_FAILURE; }
}
zHave = Z_CHUNK - zStream.avail_out;
zOutBuf[zHave] = '\0';
/* copy remainder buffer onto line buffer, if not NULL */
if (zRemainderBuf) {
strncpy(zLineBuf, zRemainderBuf, strlen(zRemainderBuf));
zBufOffset = strlen(zRemainderBuf);
}
else
zBufOffset = 0;
/* read through zOutBuf for newlines */
for (zBufIdx = zBufOffset, zOutBufIdx = 0; zOutBufIdx < zHave; zBufIdx++, zOutBufIdx++) {
zLineBuf[zBufIdx] = zOutBuf[zOutBufIdx];
if (zLineBuf[zBufIdx] == '\n') {
zLineBuf[zBufIdx] = '\0';
zBufIdx = -1;
fprintf(stdout, "%s\n", zLineBuf);
}
}
/* copy some of line buffer onto the remainder buffer, if there are remnants from the z-stream */
if (strlen(zLineBuf) > 0) {
if (strlen(zLineBuf) > strlen(zRemainderBuf)) {
/* to minimize the chance of doing another (expensive) malloc, we double the length of zRemainderBuf */
free(zRemainderBuf);
zRemainderBuf = malloc(strlen(zLineBuf) * 2);
}
strncpy(zRemainderBuf, zLineBuf, zBufIdx);
zRemainderBuf[zBufIdx] = '\0';
}
} while (zStream.avail_out == 0);
} while (zError != Z_STREAM_END);
/* close gzip stream */
zError = inflateEnd(&zStream);
if (zError != Z_OK) {
fprintf(stderr, "could not close z-stream!\n");
return EXIT_FAILURE;
}
if (zRemainderBuf)
free(zRemainderBuf);
fclose(inFp);
return EXIT_SUCCESS;
}
With any streaming you should consider the memory requirements of your app.
A good buffer size is large, but you do not want to have too much memory in use depending on your RAM usage requirements. A small buffer size will require you call your read and write operations more times which are expensive in terms of time performance. So, you need to find a buffer in the middle of those two extremes.
Typically I use a size of 4096 (4KB) which is sufficiently large for many purposes. If you want, you can go larger. But at the worst case size of 1 byte, you will be waiting a long time for you read to complete.
So to answer your question, there is no "right" size to pick. It is a choice you should make so that the speed of your app and the memory it requires are what you need.

How to use libjpeg to read a JPEG from a std::istream?

libjpeg can read JPEG data from a FILE* or a buffer. My data is coming from a std::istream. I could read the entire std::istream into a buffer to use with libjpeg, but I'd rather have libjpeg read directly from the std::istream if possible. How can this be done?
You just need to provide wrappers around your istream. Define a struct, for instance
struct JpegStream {
jpeg_source_mgr pub;
std::istream* stream;
byte buffer [4096];
}
Then you need four methods to operate on the stream:
void init_source (j_decompress_ptr cinfo)
{
auto src = (JpegStream*)(cinfo->src);
src->stream-> // seek to 0 here
}
boolean fill_buffer (j_decompress_ptr cinfo)
{
// Read to buffer
JpegStream* src = // as above
src->pub.next_input_byte = src->buffer;
src->pub.bytes_in_buffer = // How many yo could read
return eof() ? FALSE : TRUE;
}
void skip (j_decompress_ptr cinfo, long count)
{
// Seek by count bytes forward
// Make sure you know how much you have cached and subtract that
// set bytes_in_buffer and next_input_byte
}
void term (j_decompress_ptr cinfo)
{
// Close the stream, can be nop
}
and one method to bind them to the JPEG decompression info structure:
void make_stream (j_decompress_ptr cinfo, std::istream* in)
{
JpegStream * src;
/* The source object and input buffer are made permanent so that a series
* of JPEG images can be read from the same file by calling jpeg_stdio_src
* only before the first one. (If we discarded the buffer at the end of
* one image, we'd likely lose the start of the next one.)
* This makes it unsafe to use this manager and a different source
* manager serially with the same JPEG object. Caveat programmer.
*/
if (cinfo->src == NULL)
{
/* first time for this JPEG object? */
cinfo->src = (struct jpeg_source_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, POOL_PERMANENT, sizeof(JpegStream));
src = reinterpret_cast<JpegStream*> (cinfo->src);
}
src = reinterpret_cast<JpegStream*> (cinfo->src);
src->pub.init_source = init_source;
src->pub.fill_input_buffer = fill_buffer;
src->pub.skip_input_data = skip;
src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
src->pub.term_source = term;
src->stream = in;
src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
src->pub.next_input_byte = NULL; /* until buffer loaded */
}
After calling jpeg_create_decompress, call your make_stream function.

libjpeg ver. 6b jpeg_stdio_src vs jpeg_mem_src

I am using Libjpeg version 6b. In version 8 they have a nice function to read data out of the memory called jpeg_mem_src(...), unfortunately ver. 6b does not have this function.
What can I use to read compressed data directly from memory? All I see is jpeg_stdio_src which reads from the hard drive.
Write your own...
/* Read JPEG image from a memory segment */
static void init_source (j_decompress_ptr cinfo) {}
static boolean fill_input_buffer (j_decompress_ptr cinfo)
{
ERREXIT(cinfo, JERR_INPUT_EMPTY);
return TRUE;
}
static void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
{
struct jpeg_source_mgr* src = (struct jpeg_source_mgr*) cinfo->src;
if (num_bytes > 0) {
src->next_input_byte += (size_t) num_bytes;
src->bytes_in_buffer -= (size_t) num_bytes;
}
}
static void term_source (j_decompress_ptr cinfo) {}
static void jpeg_mem_src (j_decompress_ptr cinfo, void* buffer, long nbytes)
{
struct jpeg_source_mgr* src;
if (cinfo->src == NULL) { /* first time for this JPEG object? */
cinfo->src = (struct jpeg_source_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
SIZEOF(struct jpeg_source_mgr));
}
src = (struct jpeg_source_mgr*) cinfo->src;
src->init_source = init_source;
src->fill_input_buffer = fill_input_buffer;
src->skip_input_data = skip_input_data;
src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
src->term_source = term_source;
src->bytes_in_buffer = nbytes;
src->next_input_byte = (JOCTET*)buffer;
}
and then to use it:
...
/* Step 2: specify data source (eg, a file) */
jpeg_mem_src(&dinfo, buffer, nbytes);
...
where buffer is a pointer to the memory chunk containing the compressed jpeg image, and nbytes is the length of that buffer.
Answering to poor s093294 who has been waiting for an answer for more than a year. I can't comment, so creating a new answer is the only way.
ERREXIT is a macro in libjpeg. Include jerror.h and you're all set.
Or you can also try to use GNU's fmemopen() function which should be declared in stdio.h header file.
FILE * source = fmemopen(inbuffer, inlength, "rb");
if (source == NULL)
{
fprintf(stderr, "Calling fmemopen() has failed.\n");
exit(1);
}
// ...
jpeg_stdio_src(&cinfo, source);
// ...
fclose(source);

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.