📄 j2g_fiddle.c
字号:
/*****************************************************************************/
/* Copyright 2000, Hewlett-Packard Company */
/* All rights reserved */
/* File: "j2g_fiddle.c" */
/* Description: Reads and fiddles with JPEG2000 codestreams at a superficial */
/* level. Expects a codestream generated using the current */
/* version of the VM, with the `-Bresync' and `-Beph' switches */
/* enabled. Provides various facilities for massaging the */
/* codestream to test decompressor compliance. Examples */
/* breaking tiles into tile-parts, packing packet heads into */
/* PPT/PPM markers, writing pointer markers (PLT, PLM or TLM), */
/* reordering tiles, reordering markers within the global */
/* or any tile-part header, and stripping in-data and/or */
/* pointer markers. This functionality is expected to */
/* be added incrementally. The program should also eventually */
/* include the capability to introduce errors into the */
/* for error resilience testing. Basically, any codestream */
/* manipulation which is useful for testing decompressor */
/* compliance and functionality, yet which does not affect */
/* coding parameters, should be introduced here, rather than */
/* in the VM, to avoid cluttering the VM with code which has */
/* nothing to do with the compression process itself. */
/* Author: David Taubman */
/* Affiliation: Hewlett-Packard and */
/* The University of New South Wales, Australia */
/* Version: VM9.0 */
/* Last Revised: 18 April, 2001 */
/*****************************************************************************/
/*****************************************************************************/
/* Modified by David Taubman to implement changes in Tokyo between CD and */
/* FCD for Part-1 of the standard. Copyrighted by HP with all rights */
/* reserved for the modified parts. */
/*****************************************************************************/
/*****************************************************************************/
/* Modified by Gene Wu to add PLT markers option. */
/* All changes copyright 2000 by Ricoh Silicon Valley with all rights */
/* reserved for the modified parts. */
/*****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <ifc.h>
#include <local_services.h>
#include <markers.h>
#include "j2g_fiddle.h"
/*****************************************************************************/
/* STATIC complete_marker */
/*****************************************************************************/
static j2g_marker_ptr
complete_marker(std_ushort code, int buf_bytes, std_byte *buf)
{
j2g_marker_ptr result;
result = (j2g_marker_ptr) local_malloc("FIDDLE",sizeof(j2g_marker));
result->marker_code = code;
result->total_bytes = buf_bytes;
result->buf = result->buf_handle = (std_byte *)
local_malloc("FIDDLE",(size_t) buf_bytes);
result->next = NULL;
memcpy(result->buf,buf,(size_t) buf_bytes);
local_free(buf);
return(result);
}
/*****************************************************************************/
/* STATIC read_marker */
/*****************************************************************************/
static j2g_marker_ptr
read_marker(FILE *fp, std_ushort *have_marker_code)
/* This is the core codestream reading utility. It reads the next marker
segment from the codestream. For most marker segments, the length of the
segment is available in the two bytes following the marker code itself;
the only acceptable exceptions currently are: the delimiters: SOC, EOC
and SOD; and the in-data marker codes SOP and EPH. EPH markers are entirely
ignored here. SOP markers are treated specially, since they have no length
field, but the segment is assumed to run until the next SOP, SOT or EOC
marker -- this is how packets are extracted from the codestream. Due to
this behaviour, it is possible to read the marker code of the next marker
segment. For this reason, the `have_marker_code' argument is used to
keep track of marker codes which have already been read. On entry,
*`have_marker_code' should be 0 or else hold the marker code for the
marker segment being requested. On exit, it holds 0 unless we read the
marker code for an ensuing segment. */
{
std_byte *buf;
int max_buf_bytes, buf_bytes;
int max_length;
int byte_val;
int have_ff;
std_ushort code;
code = *have_marker_code;
*have_marker_code = 0;
if (code == 0)
{
byte_val = getc(fp);
code = (std_ushort) byte_val;
byte_val = getc(fp);
code = (code<<8) | (std_ushort) byte_val;
if (byte_val == EOF)
local_error("Unexpected end of file! Your codestream must contain "
"the EOC marker!");
}
if ((code & 0xFF00) != 0xFF00)
local_error("Error in codestream: Expected marker code! Note that "
"the codestream must contain RESYNC (SOP) markers; use the "
"VM's `-Bresync' option!");
buf_bytes = 2;
max_buf_bytes = 2000; /* A good initial size. */
buf = (std_byte *) local_malloc("FIDDLE",(size_t) max_buf_bytes);
buf[0] = (std_byte)((code >> 8) & 0x00FF);
buf[1] = (std_byte)(code & 0x00FF);
if ((code == MARKER_SOC) || (code == MARKER_EOC) || (code == MARKER_SOD))
return(complete_marker(code,buf_bytes,buf));
if (code == MARKER_EPH)
local_error("Error in codestream: EPH marker encountered outside packet "
"head context!");
buf[2] = (std_byte) getc(fp);
buf[3] = (std_byte) getc(fp);
buf_bytes += 2;
if (code == MARKER_SOP)
{
if ((buf[2] != 0) || (buf[3] != 4))
local_error("Error in codestream: SOP marker must contain a length "
"field with the value 4!");
buf[4] = (std_byte) getc(fp);
buf[5] = (std_byte) getc(fp);
buf_bytes += 2;
max_length = -1;
}
else
{
max_length = (int) buf[2];
max_length <<= 8;
max_length |= (int) buf[3];
max_length += 2;
if (max_length < buf_bytes)
local_error("Invalid marker segment length field!");
}
have_ff = 0;
while (buf_bytes != max_length)
{
if (buf_bytes == max_buf_bytes)
{
max_buf_bytes += 2000;
buf = (std_byte *) local_realloc(buf,(size_t) max_buf_bytes);
}
byte_val = getc(fp);
if (byte_val == EOF)
local_error("Unexpected end of file! Your codestream must contain "
"the EOC marker!");
buf[buf_bytes++] = (std_byte) byte_val;
if ((max_length < 0) && have_ff)
{
if ((byte_val == (MARKER_SOP & 0x00FF)) ||
(byte_val == (MARKER_SOT & 0x00FF)) ||
(byte_val == (MARKER_EOC & 0x00FF)))
{
*have_marker_code = 0xFF00 | (std_ushort) byte_val;
buf_bytes -= 2;
break;
}
}
have_ff = (byte_val == 0x00FF);
}
return(complete_marker(code,buf_bytes,buf));
}
/*****************************************************************************/
/* STATIC read_codestream */
/*****************************************************************************/
static j2g_codestream_ptr
read_codestream(FILE *fp)
{
j2g_codestream_ptr stream;
j2g_marker_ptr last, marker;
j2g_tilepart_ptr tp;
j2g_packet_ptr last_packet, packet;
std_ushort have_marker_code;
stream = (j2g_codestream_ptr) local_malloc("FIDDLE",sizeof(j2g_codestream));
memset(stream,0,sizeof(j2g_codestream));
have_marker_code = 0;
last = NULL;
tp = NULL;
last_packet = NULL;
while (((marker = read_marker(fp,&have_marker_code)) != NULL) &&
(marker->marker_code != MARKER_EOC))
{
if ((stream->global_markers == NULL) &&
(marker->marker_code != MARKER_SOC))
local_error("Input file does not commence with SOC marker!");
if (marker->marker_code == MARKER_SOT)
{ /* Start new tile-part. */
j2g_tilepart_ptr last_tp;
if (tp == NULL)
stream->tileparts = tp = (j2g_tilepart_ptr)
local_malloc("FIDDLE",sizeof(j2g_tilepart));
else
tp = tp->next = (j2g_tilepart_ptr)
local_malloc("FIDDLE",sizeof(j2g_tilepart));
memset(tp,0,sizeof(j2g_tilepart));
last = NULL;
last_packet = NULL;
tp->tnum = (int) marker->buf[4];
tp->tnum <<= 8; tp->tnum |= (int) marker->buf[5];
tp->tpart = (int) marker->buf[10];
tp->num_tparts = 0;
if (marker->total_bytes > 11)
tp->num_tparts = (int) marker->buf[11];
tp->tile_length = (std_uint) marker->buf[6];
tp->tile_length <<= 8; tp->tile_length |= (std_uint) marker->buf[7];
tp->tile_length <<= 8; tp->tile_length |= (std_uint) marker->buf[8];
tp->tile_length <<= 8; tp->tile_length |= (std_uint) marker->buf[9];
for (last_tp=stream->tileparts; last_tp != tp; last_tp=last_tp->next)
if (last_tp->tnum == tp->tnum)
break;
if (last_tp == tp)
{
tp->uses_eph = stream->global_eph;
tp->uses_resync = stream->global_resync;
}
else
{
tp->uses_eph = last_tp->uses_eph;
tp->uses_resync = last_tp->uses_resync;
}
stream->total_tileparts++;
if (tp->tpart == 0)
stream->total_tiles++;
}
else if ((marker->marker_code == MARKER_PPT) ||
(marker->marker_code == MARKER_PPM) ||
(marker->marker_code == MARKER_PLT) ||
(marker->marker_code == MARKER_PLM))
local_error("The input codestream may not currently contain any "
"of the PPT, PPM, PLT or PLM markers! These may, "
"however, be inserted by the current program!");
else if (marker->marker_code == MARKER_COD)
{
int resync, eph;
resync = (marker->buf[4] & 2) != 0;
eph = (marker->buf[4] & 4) != 0;
if (tp == NULL)
{
stream->global_eph = eph;
stream->global_resync = resync;
}
else
{
tp->uses_resync = resync;
tp->uses_eph = eph;
}
}
if (tp == NULL)
{ /* Add to global header. */
if (last == NULL)
stream->global_markers = marker;
else
last->next = marker;
}
else if (marker->marker_code == MARKER_SOP)
{
int n, have_ff;
stream->total_packets++;
tp->num_packets++;
packet = (j2g_packet_ptr)
local_malloc("FIDDLE",sizeof(j2g_packet));
packet->next = NULL;
if (last_packet == NULL)
last_packet = tp->packets = packet;
else
last_packet = last_packet->next = packet;
packet->buf_handle = marker->buf_handle;
packet->buf = marker->buf;
packet->packet_bytes = marker->total_bytes;
packet->head_bytes = 0;
have_ff = 0;
for (n=6; n < packet->packet_bytes; n++)
{
if (have_ff && (packet->buf[n] == (MARKER_EPH & 0x00FF)))
{
packet->head_bytes = n+1;
break;
}
have_ff = (packet->buf[n] == 0xFF);
}
local_free(marker);
continue;
}
else
{
if (last == NULL)
tp->markers = marker;
else
last->next = marker;
}
last = marker;
}
return(stream);
}
/*****************************************************************************/
/* STATIC write_codestream */
/*****************************************************************************/
static void
write_codestream(j2g_codestream_ptr stream, FILE *fp)
{
j2g_tilepart_ptr tp;
j2g_marker_ptr marker;
j2g_packet_ptr packet;
std_byte eoc[2];
/* Begin DST SIZ fix. */
for (marker=stream->global_markers; marker != NULL; marker=marker->next)
if ((marker->marker_code == MARKER_SOC) ||
(marker->marker_code == MARKER_SIZ))
fwrite(marker->buf,1,marker->total_bytes,fp);
for (marker=stream->global_markers; marker != NULL; marker=marker->next)
if ((marker->marker_code != MARKER_SIZ) &&
(marker->marker_code != MARKER_SOC))
fwrite(marker->buf,1,marker->total_bytes,fp);
/* End DST SIZ fix. */
for (tp=stream->tileparts; tp != NULL; tp=tp->next)
{
for (marker=tp->markers; marker != NULL; marker=marker->next)
fwrite(marker->buf,1,marker->total_bytes,fp);
for (packet=tp->packets; packet != NULL; packet=packet->next)
fwrite(packet->buf,1,packet->packet_bytes,fp);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -