📄 libmjpeg.c
字号:
/******************************************************************************* libmjpeg.c libquicktime - A library for reading and writing quicktime/avi/mp4 files. http://libquicktime.sourceforge.net Copyright (C) 2002 Heroine Virtual Ltd. Copyright (C) 2002-2007 Members of the libquicktime project. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA*******************************************************************************/ #include "lqt_private.h"#include "libmjpeg.h"#include <quicktime/colormodels.h>#include <stdlib.h>#include <string.h>#include <strings.h>#define LOG_DOMAIN "libmjpeg"/* JPEG MARKERS */#define M_SOF0 0xc0#define M_SOF1 0xc1#define M_SOF2 0xc2#define M_SOF3 0xc3#define M_SOF5 0xc5#define M_SOF6 0xc6#define M_SOF7 0xc7#define M_JPG 0xc8#define M_SOF9 0xc9#define M_SOF10 0xca#define M_SOF11 0xcb#define M_SOF13 0xcd#define M_SOF14 0xce#define M_SOF15 0xcf#define M_DHT 0xc4#define M_DAC 0xcc#define M_RST0 0xd0#define M_RST1 0xd1#define M_RST2 0xd2#define M_RST3 0xd3#define M_RST4 0xd4#define M_RST5 0xd5#define M_RST6 0xd6#define M_RST7 0xd7#define M_SOI 0xd8#define M_EOI 0xd9#define M_SOS 0xda#define M_DQT 0xdb#define M_DNL 0xdc#define M_DRI 0xdd#define M_DHP 0xde#define M_EXP 0xdf#define M_APP0 0xe0#define M_APP1 0xe1#define M_APP2 0xe2#define M_APP3 0xe3#define M_APP4 0xe4#define M_APP5 0xe5#define M_APP6 0xe6#define M_APP7 0xe7#define M_APP8 0xe8#define M_APP9 0xe9#define M_APP10 0xea#define M_APP11 0xeb#define M_APP12 0xec#define M_APP13 0xed#define M_APP14 0xee#define M_APP15 0xef#define M_JPG0 0xf0#define M_JPG13 0xfd#define M_COM 0xfe#define M_TEM 0x01#define M_ERROR 0x100#define QUICKTIME_MARKER_SIZE 0x2c#define QUICKTIME_JPEG_TAG 0x6d6a7067METHODDEF(void) mjpeg_error_exit (j_common_ptr cinfo) { /* cinfo->err really points to a mjpeg_error_mgr struct, so coerce pointer */ mjpeg_error_ptr mjpegerr = (mjpeg_error_ptr) cinfo->err; /* Always display the message. */ /* We could postpone this until after returning, if we chose. */ (*cinfo->err->output_message) (cinfo); /* Return control to the setjmp point */ longjmp(mjpegerr->setjmp_buffer, 1); }typedef struct { struct jpeg_destination_mgr pub; /* public fields */ JOCTET *buffer; /* Pointer to buffer */ mjpeg_compressor *engine; } mjpeg_destination_mgr;typedef mjpeg_destination_mgr *mjpeg_dest_ptr;/* * Initialize destination --- called by jpeg_start_compress * before any data is actually written. */METHODDEF(void) init_destination(j_compress_ptr cinfo) { mjpeg_dest_ptr dest = (mjpeg_dest_ptr)cinfo->dest; /* Set the pointer to the preallocated buffer */ if(!dest->engine->output_buffer) { dest->engine->output_buffer = lqt_bufalloc(65536); dest->engine->output_allocated = 65536; } dest->buffer = dest->engine->output_buffer; dest->pub.next_output_byte = dest->engine->output_buffer; dest->pub.free_in_buffer = dest->engine->output_allocated; }/* * Empty the output buffer --- called whenever buffer fills up. * * In typical applications, this should write the entire output buffer * (ignoring the current state of next_output_byte & free_in_buffer), * reset the pointer & count to the start of the buffer, and return TRUE * indicating that the buffer has been dumped. * * In applications that need to be able to suspend compression due to output * overrun, a FALSE return indicates that the buffer cannot be emptied now. * In this situation, the compressor will return to its caller (possibly with * an indication that it has not accepted all the supplied scanlines). The * application should resume compression after it has made more room in the * output buffer. Note that there are substantial restrictions on the use of * suspension --- see the documentation. * * When suspending, the compressor will back up to a convenient restart point * (typically the start of the current MCU). next_output_byte & free_in_buffer * indicate where the restart point will be if the current call returns FALSE. * Data beyond this point will be regenerated after resumption, so do not * write it out when emptying the buffer externally. */METHODDEF(boolean) empty_output_buffer(j_compress_ptr cinfo) { /* Allocate a bigger buffer. */ mjpeg_dest_ptr dest = (mjpeg_dest_ptr)cinfo->dest; dest->engine->output_size = dest->engine->output_allocated; dest->engine->output_allocated *= 2; dest->engine->output_buffer = realloc(dest->engine->output_buffer, dest->engine->output_allocated); dest->buffer = dest->engine->output_buffer; dest->pub.next_output_byte = dest->buffer + dest->engine->output_size; dest->pub.free_in_buffer = dest->engine->output_allocated - dest->engine->output_size; return TRUE; }/* * Terminate destination --- called by jpeg_finish_compress * after all data has been written. Usually needs to flush buffer. * * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding * application must deal with any cleanup that should happen even * for error exit. */METHODDEF(void) term_destination(j_compress_ptr cinfo) { /* Just get the length */ mjpeg_dest_ptr dest = (mjpeg_dest_ptr)cinfo->dest; dest->engine->output_size = dest->engine->output_allocated - dest->pub.free_in_buffer; }static GLOBAL(void) jpeg_buffer_dest(j_compress_ptr cinfo, mjpeg_compressor *engine) { mjpeg_dest_ptr dest; /* The destination object is made permanent so that multiple JPEG images * can be written to the same file without re-executing jpeg_stdio_dest. * This makes it dangerous to use this manager and a different destination * manager serially with the same JPEG object, because their private object * sizes may be different. Caveat programmer. */ if(cinfo->dest == NULL) { /* first time for this JPEG object? */ cinfo->dest = (struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(mjpeg_destination_mgr)); } dest = (mjpeg_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->engine = engine; }typedef struct {struct jpeg_source_mgr pub; /* public fields */JOCTET * buffer; /* start of buffer */int bytes; /* total size of buffer */ } mjpeg_source_mgr;typedef mjpeg_source_mgr* mjpeg_src_ptr;METHODDEF(void) init_source(j_decompress_ptr cinfo) { }METHODDEF(boolean) fill_input_buffer(j_decompress_ptr cinfo) { mjpeg_src_ptr src = (mjpeg_src_ptr) cinfo->src; src->buffer[0] = (JOCTET)0xFF; src->buffer[1] = (JOCTET)M_EOI; src->pub.next_input_byte = src->buffer; src->pub.bytes_in_buffer = 2; return TRUE; }METHODDEF(void) skip_input_data(j_decompress_ptr cinfo, long num_bytes) { mjpeg_src_ptr src = (mjpeg_src_ptr)cinfo->src; src->pub.next_input_byte += (size_t)num_bytes; src->pub.bytes_in_buffer -= (size_t)num_bytes; }METHODDEF(void) term_source(j_decompress_ptr cinfo) { }static GLOBAL(void) jpeg_buffer_src(j_decompress_ptr cinfo, unsigned char *buffer, long bytes) { mjpeg_src_ptr src; /* first time for this JPEG object? */ if(cinfo->src == NULL) { cinfo->src = (struct jpeg_source_mgr*) (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(mjpeg_source_mgr)); src = (mjpeg_src_ptr)cinfo->src; } src = (mjpeg_src_ptr)cinfo->src; src->pub.init_source = init_source; src->pub.fill_input_buffer = fill_input_buffer; src->pub.skip_input_data = skip_input_data; src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ src->pub.term_source = term_source; src->pub.bytes_in_buffer = bytes; src->pub.next_input_byte = buffer; src->buffer = buffer; src->bytes = bytes; }/* * Buffer handling for variable size output buffers */static void reset_buffer(unsigned char **buffer, long *size, long *allocated) { *size = 0; }static void delete_buffer(unsigned char **buffer, long *size, long *allocated) { if(*buffer) { free(*buffer); *size = 0; *allocated = 0; } }static void append_buffer(unsigned char **buffer, long *size, long *allocated, unsigned char *data, long data_size) { if(!*buffer) { *buffer = lqt_bufalloc(65536); *size = 0; *allocated = 65536; } if(*size + data_size > *allocated) { *allocated = *size + data_size; *buffer = realloc(*buffer, *allocated); } memcpy(*buffer + *size, data, data_size); *size += data_size; }static void allocate_temps(mjpeg_t *mjpeg) { int i; if(!mjpeg->temp_data) { switch(mjpeg->jpeg_color_model) { case BC_YUVJ422P: mjpeg->temp_data = lqt_bufalloc(mjpeg->coded_w * mjpeg->coded_h * 2); mjpeg->temp_rows[0] = lqt_bufalloc(sizeof(unsigned char*) * mjpeg->coded_h); mjpeg->temp_rows[1] = lqt_bufalloc(sizeof(unsigned char*) * mjpeg->coded_h); mjpeg->temp_rows[2] = lqt_bufalloc(sizeof(unsigned char*) * mjpeg->coded_h); for(i = 0; i < mjpeg->coded_h; i++) { mjpeg->temp_rows[0][i] = mjpeg->temp_data + i * mjpeg->coded_w; mjpeg->temp_rows[1][i] = mjpeg->temp_data + mjpeg->coded_w * mjpeg->coded_h + i * mjpeg->coded_w / 2; mjpeg->temp_rows[2][i] = mjpeg->temp_data + mjpeg->coded_w * mjpeg->coded_h + mjpeg->coded_w / 2 * mjpeg->coded_h + i * mjpeg->coded_w / 2; } break; case BC_YUVJ444P: mjpeg->temp_data = lqt_bufalloc(mjpeg->coded_w * mjpeg->coded_h * 3); mjpeg->temp_rows[0] = lqt_bufalloc(sizeof(unsigned char*) * mjpeg->coded_h); mjpeg->temp_rows[1] = lqt_bufalloc(sizeof(unsigned char*) * mjpeg->coded_h); mjpeg->temp_rows[2] = lqt_bufalloc(sizeof(unsigned char*) * mjpeg->coded_h); for(i = 0; i < mjpeg->coded_h; i++) { mjpeg->temp_rows[0][i] = mjpeg->temp_data + i * mjpeg->coded_w; mjpeg->temp_rows[1][i] = mjpeg->temp_data + mjpeg->coded_w * mjpeg->coded_h + i * mjpeg->coded_w; mjpeg->temp_rows[2][i] = mjpeg->temp_data + mjpeg->coded_w * mjpeg->coded_h + mjpeg->coded_w * mjpeg->coded_h + i * mjpeg->coded_w; } break; case BC_YUVJ420P: mjpeg->temp_data = lqt_bufalloc(mjpeg->coded_w * mjpeg->coded_h + mjpeg->coded_w * mjpeg->coded_h / 2); mjpeg->temp_rows[0] = lqt_bufalloc(sizeof(unsigned char*) * mjpeg->coded_h); mjpeg->temp_rows[1] = lqt_bufalloc(sizeof(unsigned char*) * mjpeg->coded_h / 2); mjpeg->temp_rows[2] = lqt_bufalloc(sizeof(unsigned char*) * mjpeg->coded_h / 2); for(i = 0; i < mjpeg->coded_h; i++) { mjpeg->temp_rows[0][i] = mjpeg->temp_data + i * mjpeg->coded_w; if(i < mjpeg->coded_h / 2) { mjpeg->temp_rows[1][i] = mjpeg->temp_data + mjpeg->coded_w * mjpeg->coded_h + i * (mjpeg->coded_w / 2); mjpeg->temp_rows[2][i] = mjpeg->temp_data + mjpeg->coded_w * mjpeg->coded_h + (mjpeg->coded_h / 2) * (mjpeg->coded_w / 2) + i * (mjpeg->coded_w / 2); } } break; } } }static int get_input_row(mjpeg_t *mjpeg, int i, int field) { int input_row; if(mjpeg->fields > 1) input_row = i * 2 + field; else input_row = i; if(input_row >= mjpeg->coded_h) input_row = mjpeg->coded_h - 1; return input_row; }// Get pointers to rows for the JPEG compressorstatic void get_rows(mjpeg_t *mjpeg, mjpeg_compressor *compressor, int field) { int i; if((mjpeg->fields > 1) && (mjpeg->bottom_first)) field = 1 - field; switch(mjpeg->jpeg_color_model) { case BC_YUVJ444P: { if(!compressor->rows[0]) { compressor->rows[0] = lqt_bufalloc(sizeof(unsigned char*) * compressor->field_h); compressor->rows[1] = lqt_bufalloc(sizeof(unsigned char*) * compressor->field_h); compressor->rows[2] = lqt_bufalloc(sizeof(unsigned char*) * compressor->field_h); } for(i = 0; i < compressor->field_h; i++) { int input_row = get_input_row(mjpeg, i, field); compressor->rows[0][i] = mjpeg->temp_rows[0][input_row]; compressor->rows[1][i] = mjpeg->temp_rows[1][input_row]; compressor->rows[2][i] = mjpeg->temp_rows[2][input_row]; } break; } case BC_YUVJ422P: { if(!compressor->rows[0]) { compressor->rows[0] = lqt_bufalloc(sizeof(unsigned char*) * compressor->field_h); compressor->rows[1] = lqt_bufalloc(sizeof(unsigned char*) * compressor->field_h); compressor->rows[2] = lqt_bufalloc(sizeof(unsigned char*) * compressor->field_h); } for(i = 0; i < compressor->field_h; i++) { int input_row = get_input_row(mjpeg, i, field); compressor->rows[0][i] = mjpeg->temp_rows[0][input_row]; compressor->rows[1][i] = mjpeg->temp_rows[1][input_row]; compressor->rows[2][i] = mjpeg->temp_rows[2][input_row]; } break; } case BC_YUVJ420P: { if(!compressor->rows[0]) { compressor->rows[0] = lqt_bufalloc(sizeof(unsigned char*) * mjpeg->coded_h); compressor->rows[1] = lqt_bufalloc(sizeof(unsigned char*) * mjpeg->coded_h / 2); compressor->rows[2] = lqt_bufalloc(sizeof(unsigned char*) * mjpeg->coded_h / 2); } for(i = 0; i < compressor->field_h; i++) { int input_row = get_input_row(mjpeg, i, field); compressor->rows[0][i] = mjpeg->temp_rows[0][input_row]; if(i < compressor->field_h / 2) { compressor->rows[1][i] = mjpeg->temp_rows[1][input_row]; compressor->rows[2][i] = mjpeg->temp_rows[2][input_row]; } } break; } } }static void delete_rows(mjpeg_compressor *compressor) { if(compressor->rows[0]) { free(compressor->rows[0]); free(compressor->rows[1]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -