#include <errno.h>
#include <png.h>
+#include <jpeglib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
long VFrame::get_data_size()
{
- return calculate_data_size(w, h, bytes_per_line, color_model) - 4;
+ return calculate_data_size(w, h, bytes_per_line, color_model) - BC_COLOR_ALIGN;
}
long VFrame::calculate_data_size(int w, int h, int bytes_per_line, int color_model)
bytes_per_line : this->bytes_per_pixel * w;
// Allocate data + padding for MMX
- if(data) {
+ if( data ) {
//printf("VFrame::allocate_data %d %p\n", __LINE__, this->data);
memory_type = VFrame::SHARED;
this->data = data;
this->u_offset = u_offset;
this->v_offset = v_offset;
}
- else if(shmid >= 0) {
+ else if( shmid >= 0 ) {
memory_type = VFrame::SHMGET;
this->data = (unsigned char*)shmat(shmid, NULL, 0);
+ if( this->data == (unsigned char*)-1 ) {
+ printf("VFrame::allocate_data %d could not attach"
+ " shared memory, %dx%d (model %d) shmid=0x%08x\n",
+ __LINE__, w, h, color_model, shmid);
+ BC_Trace::dump_shm_stats(stdout);
+ exit(1);
+ }
//printf("VFrame::allocate_data %d shmid=%d data=%p\n", __LINE__, shmid, this->data);
this->shmid = shmid;
this->y_offset = y_offset;
this->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777);
if( this->shmid >= 0 ) {
this->data = (unsigned char*)shmat(this->shmid, NULL, 0);
-//printf("VFrame::allocate_data %d %d %d %p\n", __LINE__, size, this->shmid, this->data);
-// This causes it to automatically delete when the program exits.
- shmctl(this->shmid, IPC_RMID, 0);
+ if( this->data == (unsigned char *)-1 ) this->data = 0;
}
- else {
+ if( !this->data ) {
printf("VFrame::allocate_data %d could not allocate"
" shared memory, %dx%d (model %d) size=0x%08x\n",
__LINE__, w, h, color_model, size);
BC_Trace::dump_shm_stats(stdout);
+ exit(1);
}
+// This causes it to automatically delete when the program exits.
+ shmctl(this->shmid, IPC_RMID, 0);
}
-// Have to use malloc for libpng
- if( !this->data ) {
+ else {
this->data = (unsigned char *)malloc(size);
+ if( !this->data ) {
+ printf("VFrame::allocate_data %dx%d: memory exhausted.\n", this->w, this->h);
+ exit(1);
+ }
this->shmid = -1;
}
// Memory check
// printf("VFrame::allocate_data 2 this=%p w=%d h=%d this->data=%p\n",
// this, this->w, this->h, this->data);
- if(!this->data)
- printf("VFrame::allocate_data %dx%d: memory exhausted.\n", this->w, this->h);
#ifdef LEAKER
printf("==new %p from %p sz %d\n", this->data, __builtin_return_address(0), size);
#endif
int VFrame::allocate_compressed_data(long bytes)
{
- if(bytes < 1) return 1;
+ if( bytes < 1 ) return 1;
// Want to preserve original contents
- if(data && compressed_allocated < bytes)
- {
+ if( data && compressed_allocated < bytes ) {
int new_shmid = -1;
unsigned char *new_data = 0;
- if(BC_WindowBase::get_resources()->use_vframe_shm() && use_shm)
- {
- new_shmid = shmget(IPC_PRIVATE,
- bytes,
- IPC_CREAT | 0777);
- new_data = (unsigned char*)shmat(new_shmid, NULL, 0);
+ if( BC_WindowBase::get_resources()->use_vframe_shm() && use_shm ) {
+ new_shmid = shmget(IPC_PRIVATE, bytes, IPC_CREAT | 0777);
+ if( new_shmid >= 0 ) {
+ new_data = (unsigned char *) shmat(new_shmid, NULL, 0);
+ if( new_data == (unsigned char *)-1 ) new_data = 0;
+ }
+ if( !new_data ) {
+ printf("VFrame::allocate_compressed_data %d could not allocate"
+ " shared memory, %ld\n", __LINE__, bytes);
+ BC_Trace::dump_shm_stats(stdout);
+ exit(1);
+ }
shmctl(new_shmid, IPC_RMID, 0);
}
- else
- {
+ else {
// Have to use malloc for libpng
new_data = (unsigned char *)malloc(bytes);
+ if( !new_data ) {
+ printf("VFrame::allocate_compressed_data %ld: memory exhausted.\n", bytes);
+ exit(1);
+ }
}
bcopy(data, new_data, compressed_allocated);
UNBUFFER(data);
- if(memory_type == VFrame::PRIVATE)
- {
- if(shmid > 0) {
- if(data)
- shmdt(data);
+ if( memory_type == VFrame::PRIVATE ) {
+ if( shmid > 0 ) {
+ if( data ) shmdt(data);
}
else
free(data);
}
- else
- if(memory_type == VFrame::SHMGET)
- {
- if(data)
- shmdt(data);
+ else if( memory_type == VFrame::SHMGET ) {
+ if( data ) shmdt(data);
}
data = new_data;
shmid = new_shmid;
compressed_allocated = bytes;
}
- else
- if(!data)
- {
- if(BC_WindowBase::get_resources()->use_vframe_shm() && use_shm)
- {
- shmid = shmget(IPC_PRIVATE,
- bytes,
- IPC_CREAT | 0777);
- data = (unsigned char*)shmat(shmid, NULL, 0);
+ else if( !data ) {
+ if( BC_WindowBase::get_resources()->use_vframe_shm() && use_shm ) {
+ shmid = shmget(IPC_PRIVATE, bytes, IPC_CREAT | 0777);
+ if( shmid >= 0 ) {
+ data = (unsigned char *)shmat(shmid, NULL, 0);
+ if( data == (unsigned char *)-1 ) data = 0;
+ }
+ if( !data ) {
+ printf("VFrame::allocate_compressed_data %d: could not allocate"
+ " shared memory, %ld\n", __LINE__, bytes);
+ BC_Trace::dump_shm_stats(stdout);
+ exit(1);
+ }
shmctl(shmid, IPC_RMID, 0);
}
- else
- {
+ else {
// Have to use malloc for libpng
data = (unsigned char *)malloc(bytes);
+ if( !data ) {
+ printf("VFrame::allocate_compressed_data %d: memory exhausted, %ld\n",
+ __LINE__, bytes);
+ exit(1);
+ }
}
compressed_allocated = bytes;
if (src_color_model == PNG_COLOR_TYPE_GRAY && png_get_bit_depth(png_ptr, info_ptr) < 8)
png_set_expand(png_ptr);
- if (src_color_model == PNG_COLOR_TYPE_GRAY ||
- src_color_model == PNG_COLOR_TYPE_GRAY_ALPHA)
+ if (src_color_model == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr);
/* expand paletted or RGB images with transparency to full alpha channels
png_set_expand(png_ptr);
}
- switch(src_color_model)
- {
- case PNG_COLOR_TYPE_GRAY:
- case PNG_COLOR_TYPE_RGB:
- new_color_model = BC_RGB888;
- break;
-
- case PNG_COLOR_TYPE_GRAY_ALPHA:
- case PNG_COLOR_TYPE_RGB_ALPHA:
- default:
- new_color_model = BC_RGBA8888;
- break;
-
- case PNG_COLOR_TYPE_PALETTE:
- if(have_alpha)
- new_color_model = BC_RGBA8888;
- else
- new_color_model = BC_RGB888;
+ switch(src_color_model) {
+ case PNG_COLOR_TYPE_GRAY:
+ new_color_model = BC_GREY8;
+ break;
+ case PNG_COLOR_TYPE_RGB:
+ new_color_model = BC_RGB888;
+ break;
+ case PNG_COLOR_TYPE_PALETTE:
+ new_color_model = have_alpha ? BC_RGBA8888 : BC_RGB888;
+ break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ default:
+ new_color_model = BC_RGBA8888;
+ break;
}
-
reallocate(NULL, -1, 0, 0, 0, w, h, new_color_model, -1);
//printf("VFrame::read_png %d %d %d %p\n", __LINE__, w, h, get_rows());
int VFrame::copy_from(VFrame *frame)
{
- if(this->w != frame->get_w() ||
- this->h != frame->get_h())
- {
+ if( this->w != frame->get_w() ||
+ this->h != frame->get_h() ) {
printf("VFrame::copy_from %d sizes differ src %dx%d != dst %dx%d\n",
- __LINE__,
- frame->get_w(),
- frame->get_h(),
- get_w(),
- get_h());
+ __LINE__, frame->get_w(), frame->get_h(), get_w(), get_h());
return 1;
}
int h = MIN(this->h, frame->get_h());
timestamp = frame->timestamp;
- switch(frame->color_model)
- {
- case BC_COMPRESSED:
- allocate_compressed_data(frame->compressed_size);
- memcpy(data, frame->data, frame->compressed_size);
- this->compressed_size = frame->compressed_size;
- break;
+ switch( frame->color_model ) {
+ case BC_COMPRESSED:
+ allocate_compressed_data(frame->compressed_size);
+ memcpy(data, frame->data, frame->compressed_size);
+ this->compressed_size = frame->compressed_size;
+ break;
- case BC_YUV410P:
- memcpy(get_y(), frame->get_y(), w * h);
- memcpy(get_u(), frame->get_u(), w / 4 * h / 4);
- memcpy(get_v(), frame->get_v(), w / 4 * h / 4);
- break;
+ case BC_YUV410P:
+ memcpy(get_y(), frame->get_y(), w * h);
+ memcpy(get_u(), frame->get_u(), w / 4 * h / 4);
+ memcpy(get_v(), frame->get_v(), w / 4 * h / 4);
+ break;
- case BC_YUV420P:
- case BC_YUV420PI:
- case BC_YUV411P:
+ case BC_YUV420P:
+ case BC_YUV420PI:
+ case BC_YUV411P:
//printf("%d %d %p %p %p %p %p %p\n", w, h, get_y(), get_u(), get_v(), frame->get_y(), frame->get_u(), frame->get_v());
- memcpy(get_y(), frame->get_y(), w * h);
- memcpy(get_u(), frame->get_u(), w * h / 4);
- memcpy(get_v(), frame->get_v(), w * h / 4);
- break;
+ memcpy(get_y(), frame->get_y(), w * h);
+ memcpy(get_u(), frame->get_u(), w * h / 4);
+ memcpy(get_v(), frame->get_v(), w * h / 4);
+ break;
- case BC_YUV422P:
+ case BC_YUV422P:
//printf("%d %d %p %p %p %p %p %p\n", w, h, get_y(), get_u(), get_v(), frame->get_y(), frame->get_u(), frame->get_v());
- memcpy(get_y(), frame->get_y(), w * h);
- memcpy(get_u(), frame->get_u(), w * h / 2);
- memcpy(get_v(), frame->get_v(), w * h / 2);
- break;
+ memcpy(get_y(), frame->get_y(), w * h);
+ memcpy(get_u(), frame->get_u(), w * h / 2);
+ memcpy(get_v(), frame->get_v(), w * h / 2);
+ break;
- case BC_YUV444P:
+ case BC_YUV444P:
//printf("%d %d %p %p %p %p %p %p\n", w, h, get_y(), get_u(), get_v(), frame->get_y(), frame->get_u(), frame->get_v());
- memcpy(get_y(), frame->get_y(), w * h);
- memcpy(get_u(), frame->get_u(), w * h);
- memcpy(get_v(), frame->get_v(), w * h);
- break;
- default:
-// printf("VFrame::copy_from %d\n", calculate_data_size(w,
-// h,
-// -1,
-// frame->color_model));
+ memcpy(get_y(), frame->get_y(), w * h);
+ memcpy(get_u(), frame->get_u(), w * h);
+ memcpy(get_v(), frame->get_v(), w * h);
+ break;
+ default:
+// printf("VFrame::copy_from %d\n", calculate_data_size(w, h, -1, frame->color_model));
// Copy without extra 4 bytes in case the source is a hardware device
- memmove(data, frame->data, get_data_size());
- break;
+ memmove(data, frame->data, get_data_size());
+ break;
}
return 0;
}
+// jpeg decompress
+class jpeg_err : public jpeg_error_mgr
+{
+ static void s_error_exit(j_common_ptr cp);
+ static void s_output_message(j_common_ptr cp);
+public:
+ jpeg_err() {
+ jpeg_std_error((jpeg_error_mgr *)this);
+ error_exit = s_error_exit;
+ output_message = s_output_message;
+ }
+ ~jpeg_err() {}
+};
+
+class jpeg_src : public jpeg_source_mgr
+{
+ static void s_init_source(j_decompress_ptr jp);
+ static boolean s_fill_input_buffer(j_decompress_ptr jp);
+ static void s_skip_input_data(j_decompress_ptr jp, long len);
+ static void s_term_source(j_decompress_ptr jp);
+ static boolean s_resync_to_restart(j_decompress_ptr jp, int v);
+public:
+ jpeg_src();
+ ~jpeg_src();
+ int jpeg_file(int fd);
+ int jpeg_mem(const unsigned char *bfr, long len);
+
+ int fd;
+ unsigned char *mbfr;
+ long mlen;
+ enum { buffer_sz=0x10000, file_sz=0x100000, };
+ unsigned char *buffer;
+ boolean fill_buffer();
+ void skip_data(long len);
+};
+
+class JpegVFrame : public jpeg_decompress_struct
+{
+public:
+ JpegVFrame();
+ ~JpegVFrame();
+ int read_jpeg(VFrame *vfrm, double xs, double ys, int jpeg_model);
+
+ jpeg_err jerr;
+ jpeg_src jsrc;
+ int debug, ret;
+};
+
+
+void jpeg_err:: s_error_exit(j_common_ptr cp)
+{
+ JpegVFrame *jpeg = (JpegVFrame *)cp;
+ jpeg->ret = 1;
+ if( !jpeg->debug ) return;
+ printf("s_error_exit()\n");
+}
+
+void jpeg_err::
+s_output_message(j_common_ptr cp)
+{
+ JpegVFrame *jpeg = (JpegVFrame *)cp;
+ if( !jpeg->debug ) return;
+ char msg[JMSG_LENGTH_MAX];
+ (*cp->err->format_message)(cp, msg);
+ printf("s_output_message() = %s\n",&msg[0]);
+}
+
+
+jpeg_src::jpeg_src()
+{
+ init_source = s_init_source;
+ fill_input_buffer = s_fill_input_buffer;
+ skip_input_data = s_skip_input_data;
+ resync_to_restart = s_resync_to_restart;
+ term_source = s_term_source;
+
+ fd = -1;
+ buffer = 0;
+ mbfr = 0;
+ mlen = -1;
+}
+
+jpeg_src::~jpeg_src()
+{
+ if( mbfr ) ::munmap(mbfr, mlen);
+ delete [] buffer;
+}
+
+int jpeg_src::jpeg_file(int fd)
+{
+ this->fd = fd;
+ struct stat st;
+ if( fstat(fd, &st) || !st.st_size ) return 0;
+ if( st.st_size < file_sz ) {
+ mbfr = (unsigned char *)::mmap(0, mlen = st.st_size,
+ PROT_READ, MAP_SHARED, fd, 0);
+ if( mbfr == MAP_FAILED ) return 0;
+ next_input_byte = mbfr;
+ bytes_in_buffer = mlen;
+ }
+ else {
+ buffer = new unsigned char[buffer_sz];
+ next_input_byte = &buffer[0];
+ bytes_in_buffer = 0;
+ }
+ return 1;
+}
+int jpeg_src::jpeg_mem(const unsigned char *bfr, long len)
+{
+ next_input_byte = bfr;
+ bytes_in_buffer = len;
+ return 1;
+}
+
+void jpeg_src::s_init_source(j_decompress_ptr jp) {}
+void jpeg_src::s_term_source(j_decompress_ptr jp) {}
+
+boolean jpeg_src::s_resync_to_restart(j_decompress_ptr jp, int v)
+{
+ return jpeg_resync_to_restart(jp, v);
+}
+
+boolean jpeg_src::s_fill_input_buffer(j_decompress_ptr jp)
+{
+ JpegVFrame *jpeg = (JpegVFrame *)jp;
+ return jpeg->jsrc.fill_buffer();
+}
+
+boolean jpeg_src::fill_buffer()
+{
+ if( mbfr || fd < 0 ) return 0;
+ long n = ::read(fd, buffer, buffer_sz);
+ if( n < 0 ) perror("jpeg read");
+ if( !n ) return 0;
+ next_input_byte = buffer;
+ bytes_in_buffer = n;
+ return 1;
+}
+
+void jpeg_src::s_skip_input_data(j_decompress_ptr jp, long len)
+{
+ JpegVFrame *jpeg = (JpegVFrame *)jp;
+ jpeg->jsrc.skip_data(len);
+}
+
+void jpeg_src::skip_data(long len)
+{
+ while( len > (long) bytes_in_buffer ) {
+ len -= (long) bytes_in_buffer;
+ if( !fill_buffer() ) return;
+ }
+ next_input_byte += len;
+ bytes_in_buffer -= len;
+}
+
+
+JpegVFrame::JpegVFrame()
+{
+ jpeg_create_decompress(this);
+ debug = 1; ret = 0;
+ err = &jerr; src = &jsrc;
+}
+JpegVFrame::~JpegVFrame()
+{
+ jpeg_destroy_decompress(this);
+}
+
+int JpegVFrame::read_jpeg(VFrame *vfrm, double xs, double ys, int jpeg_model)
+{
+ VFrame *xfrm = vfrm;
+ int color_model = xfrm->get_color_model();
+ if( color_model == BC_COMPRESSED ) color_model = jpeg_model;
+ jpeg_abort((jpeg_common_struct *)this);
+ if( jpeg_read_header(this, TRUE) != JPEG_HEADER_OK ) return 0;
+ jpeg_calc_output_dimensions(this);
+ quantize_colors = FALSE;
+ out_color_space =
+ jpeg_model == BC_YUV888 ? JCS_YCbCr :
+ jpeg_model == BC_GREY8 ? JCS_GRAYSCALE : JCS_RGB;
+ jpeg_calc_output_dimensions(this);
+ int w = bmax(image_width*xs, 1.);
+ int h = bmax(image_height*ys, 1.);
+ vfrm->reallocate(0, -1, 0, 0, 0, w, h, color_model, -1);
+ if( w != (int)image_width || h != (int)image_height ||
+ color_model != jpeg_model )
+ xfrm = new VFrame(image_width, image_height, jpeg_model);
+ unsigned char *pic = xfrm->get_data();
+ int linesz = xfrm->get_bytes_per_line();
+ jpeg_start_decompress(this);
+ while( !ret && output_scanline < image_height ) {
+ JSAMPROW rowptr = (JSAMPROW) &pic[output_scanline * linesz];
+ jpeg_read_scanlines(this, &rowptr, (JDIMENSION) 1);
+ }
+ jpeg_finish_decompress(this);
+ if( vfrm != xfrm ) {
+ vfrm->transfer_from(xfrm);
+ delete xfrm;
+ }
+ return 1;
+}
+
+int VFrameJpeg::read_jpeg(const unsigned char *data, long sz,
+ double xscale, double yscale, int jpeg_model)
+{
+ JpegVFrame jpeg;
+ jpeg.jsrc.jpeg_mem(data, sz);
+ return jpeg.read_jpeg(this, xscale, yscale, jpeg_model);
+}
+
+VFrameJpeg::VFrameJpeg(const unsigned char *jpeg_data, double s)
+{
+ long image_size =
+ ((long)jpeg_data[0] << 24) | ((long)jpeg_data[1] << 16) |
+ ((long)jpeg_data[2] << 8) | (long)jpeg_data[3];
+ if( !s ) s = BC_WindowBase::get_resources()->icon_scale;
+ read_jpeg(jpeg_data+4, image_size, s, s, BC_RGB888);
+}
+
+VFrameJpeg::VFrameJpeg(const unsigned char *jpeg_data, long image_size, double xs, double ys)
+{
+ if( !xs ) xs = BC_WindowBase::get_resources()->icon_scale;
+ if( !ys ) ys = BC_WindowBase::get_resources()->icon_scale;
+ read_jpeg(jpeg_data, image_size, xs, ys, BC_RGB888);
+}
+
+VFrameJpeg::~VFrameJpeg()
+{
+}
+
+
+VFrame *VFrameJpeg::vframe_jpeg(int fd, double xs, double ys, int jpeg_model)
+{
+ JpegVFrame jpeg;
+ jpeg.jsrc.jpeg_file(fd);
+ VFrame *vfrm = new VFrame();
+ if( !jpeg.read_jpeg(vfrm, xs, ys, jpeg_model) ) {
+ delete vfrm; vfrm = 0;
+ }
+ return vfrm;
+}
+
+VFrame *VFrameJpeg::vframe_jpeg(const char *jpeg_path, double xs, double ys, int jpeg_model)
+{
+ VFrame *vframe = 0;
+ int fd = ::open(jpeg_path, O_RDONLY);
+ if( fd >= 0 ) {
+ vframe = vframe_jpeg(fd, xs, ys, jpeg_model);
+ ::close(fd);
+ }
+ return vframe;
+}
+