|
From: Luis F. S. M. <lui...@us...> - 2006-06-17 08:14:09
|
Update of /cvsroot/dirac/soc_javadec_luis/decoder In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv6715/decoder Added Files: ByteIO.java Decoder.java Status.java Log Message: Initial commit. The Decoder is parsing (correctly as far as I know) everything before the data block. Sorry for the earlier empty directories commited. --- NEW FILE: Decoder.java --- /* * This file is part of Landell. * * Landell is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * Landell 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Landell; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ /** * */ package decoder; import java.io.*; import frame.*; import debug.*; /** * @author lfelipe * */ public class Decoder { private BufferedInputStream input; private Status status; private Frame frame; private boolean finished; /** * This constructor should never be used */ public Decoder () { Debug.printError(this, "No streams given, aborting"); } /** * Opens a local file for decoding * * @param file - the string containing the name of the local file to be opened */ public Decoder (String file) { this.setStatus(Status.SEQUENCE_START); this.frame = new Frame(); try { this.input = new BufferedInputStream(new FileInputStream(file)); } catch (FileNotFoundException e) { // FIXME: do something here } this.finished = false; } /** * Closes the input file, probably better than leaving it up to the GC to do it, * if it even does it, which I'm not certain */ public void close () { try { this.input.close(); } catch (IOException e) { // FIXME: do something here } } /** * @return FIXME: must return the actual image, not void */ public void getNextFrame () { try { Debug.printMessage(this, "Bytes available on input : " + Integer.toString(this.input.available())); switch (this.status) { case SEQUENCE_START : Debug.foundSequence(); initializeSequence(); parseInfo(); setStatus(Status.ACCESS_UNIT_START); case ACCESS_UNIT_START : Debug.foundAccessUnit(); parseAccessUnitHeader(); parseInfo(); setStatus(Status.FRAME); case FRAME : Debug.foundFrame(); getPicture(); parseInfo(); break; } } catch (IOException e) { // FIXME: do something here } this.finished = true; // FIXME: this shouldn't be here, debug-purposes only } /** * * @return FIXME: should this return something ? */ private void parseInfo () { byte prefix[] = new byte[4]; byte next_offset[] = new byte[3]; byte previous_offset[] = new byte[3]; String test; try { this.input.read(prefix); test = new String(prefix); if (! "BBCD".equals(test)) { Debug.printError(this, "Expected \"BBCD\" but to " +test + " instead"); } else { Debug.printMessage(this, "Found the expected \"BBCD\" prefix"); } this.frame.parse_code = ByteIO.read_bytes(this.input, 1); // FIXME: treat the different parse codes this.input.read(next_offset); this.input.read(previous_offset); // FIXME: where should I store those ? } catch (IOException e) { // FIXME: do something here } } /** * * @return FIXME: should this return something ? */ private void parseAccessUnitHeader () { parseParameters(); sequenceParameters(); sourceParameters(); } private void parseParameters () { this.frame.au_picture_number = ByteIO.read_bytes(this.input, 4) ; this.frame.major = ByteIO.read_uint(this.input); this.frame.minor = ByteIO.read_uint(this.input); this.frame.profile = ByteIO.read_uint(this.input); this.frame.level = ByteIO.read_uint(this.input); } private void sequenceParameters () { this.frame.video_format = ByteIO.read_uint(this.input); this.frame.sequenceDefaults(); this.frame.custom_dimensions = ByteIO.read_bool(this.input); if (this.frame.custom_dimensions) { this.frame.luma_width = ByteIO.read_uint(this.input); this.frame.luma_height = ByteIO.read_uint(this.input); } this.frame.chroma_format_flag = ByteIO.read_bool(this.input); if (this.frame.chroma_format_flag) { this.frame.chroma_format_index = ByteIO.read_uint(this.input); switch ((int)this.frame.chroma_format_index) { case 0: this.frame.chroma_format = "4:4:4"; break; case 1: this.frame.chroma_format = "4:2:2"; break; case 2: this.frame.chroma_format = "4:2:0"; break; } } this.frame.video_depth_flag = ByteIO.read_bool(this.input); if (this.frame.video_depth_flag) { this.frame.video_depth = ByteIO.read_uint(this.input); } } private void sourceParameters () { this.frame.sourceDefaults(); this.frame.scan_format_flag = ByteIO.read_bool(this.input); if (this.frame.scan_format_flag) { this.frame.interlaced_source = ByteIO.read_bool(this.input); if (this.frame.interlaced_source) { this.frame.field_dominance_flag = ByteIO.read_bool(this.input); if (this.frame.field_dominance_flag) { this.frame.top_field_first = ByteIO.read_bool(this.input); } this.frame.field_interleaving_flag = ByteIO.read_bool(this.input); if (this.frame.field_interleaving_flag) { this.frame.sequential_fields = ByteIO.read_bool(this.input); } } } this.frame.frame_rate_flag = ByteIO.read_bool(this.input); if (this.frame.frame_rate_flag) { this.frame.frame_rate_index = ByteIO.read_uint(this.input); if (this.frame.frame_rate_index != 0) { switch ((int) this.frame.frame_rate_index) { case 1: this.frame.frame_rate_numerator = 24000; this.frame.frame_rate_denominator = 1001; break; case 2: this.frame.frame_rate_numerator = 24; this.frame.frame_rate_denominator = 1; break; case 3: this.frame.frame_rate_numerator = 25; this.frame.frame_rate_denominator = 1; break; case 4: this.frame.frame_rate_numerator = 30000; this.frame.frame_rate_denominator = 1001; break; case 5: this.frame.frame_rate_numerator = 30; this.frame.frame_rate_denominator = 1; break; case 6: this.frame.frame_rate_numerator = 50; this.frame.frame_rate_denominator = 1; break; case 7: this.frame.frame_rate_numerator = 60000; this.frame.frame_rate_denominator = 1001; break; case 8: this.frame.frame_rate_numerator = 60; this.frame.frame_rate_denominator = 1; break; default: // FIXME: do something here later } } else { this.frame.frame_rate_numerator = ByteIO.read_uint(this.input); this.frame.frame_rate_denominator = ByteIO.read_uint(this.input); } } this.frame.aspect_ratio_flag = ByteIO.read_bool(this.input); if (this.frame.aspect_ratio_flag) { this.frame.aspect_ratio_index = ByteIO.read_uint(this.input); if (this.frame.aspect_ratio_index != 0) { switch ((int) this.frame.aspect_ratio_index) { case 1: this.frame.aspect_ratio_numerator = 1; this.frame.aspect_ratio_denominator = 1; break; case 2: this.frame.aspect_ratio_numerator = 10; this.frame.aspect_ratio_denominator = 11; break; case 3: this.frame.aspect_ratio_numerator = 12; this.frame.aspect_ratio_denominator = 11; break; default: // FIXME: do something here later } } else { this.frame.aspect_ratio_numerator = ByteIO.read_uint(this.input); this.frame.aspect_ratio_denominator = ByteIO.read_uint(this.input); } } this.frame.clean_area_flag = ByteIO.read_bool(this.input); if (this.frame.clean_area_flag) { this.frame.clean_width = ByteIO.read_uint(this.input); this.frame.clean_height = ByteIO.read_uint(this.input); this.frame.left_offset = ByteIO.read_uint(this.input); this.frame.top_offset = ByteIO.read_uint(this.input); } this.frame.signal_range_flag = ByteIO.read_bool(this.input); if (this.frame.signal_range_flag) { this.frame.signal_range_index = ByteIO.read_uint(this.input); if (this.frame.signal_range_index != 0) { switch ((int) this.frame.signal_range_index) { case 1: // 8 bit full range this.frame.luma_offset = 0; this.frame.luma_excursion = 255; this.frame.chroma_offset = 128; this.frame.chroma_excursion = 255; break; case 2: // 8 bit video this.frame.luma_offset = 16; this.frame.luma_excursion = 235; this.frame.chroma_offset = 128; this.frame.chroma_excursion = 224; break; case 3: // 10 bit video this.frame.luma_offset = 64; this.frame.luma_excursion = 876; this.frame.chroma_offset = 512; this.frame.chroma_excursion = 896; break; default: // FIXME: do something here later } } else { this.frame.luma_offset = ByteIO.read_uint(this.input); this.frame.luma_excursion = ByteIO.read_uint(this.input); this.frame.chroma_offset = ByteIO.read_uint(this.input); this.frame.chroma_excursion = ByteIO.read_uint(this.input); } } this.frame.colour_spec_flag = ByteIO.read_bool(this.input); if (this.frame.colour_spec_flag) { this.frame.colour_spec_index = ByteIO.read_uint(this.input); if (this.frame.colour_spec_index != 0) { switch ((int) this.frame.colour_spec_index) { case 1: this.frame.colour_primaries_index = 1; this.frame.colour_matrix_index = 1; this.frame.transfer_function_index = 0; break; case 2: this.frame.colour_primaries_index = 2; this.frame.colour_matrix_index = 1; this.frame.transfer_function_index = 0; break; case 3: this.frame.colour_primaries_index = 3; this.frame.colour_matrix_index = 2; this.frame.transfer_function_index = 3; break; default: // FIXME: do something here later } } else { this.frame.colour_primaries_flag = ByteIO.read_bool(this.input); if (this.frame.colour_primaries_flag) { this.frame.colour_primaries_index = ByteIO.read_uint(this.input); } this.frame.colour_matrix_flag = ByteIO.read_bool(this.input); if (this.frame.colour_matrix_flag) { this.frame.colour_matrix_index = ByteIO.read_uint(this.input); } this.frame.transfer_function_flag = ByteIO.read_bool(this.input); if (this.frame.transfer_function_flag) { this.frame.transfer_function_index = ByteIO.read_uint(this.input); } } switch ((int) this.frame.colour_primaries_index) { case 0: this.frame.colour_primaries = "ITU_709"; break; case 1: this.frame.colour_primaries = "SMPTE_C"; break; case 2: this.frame.colour_primaries = "EBU_3213"; break; case 3: this.frame.colour_primaries = "CIE_XYZ"; break; default: // FIXME: do something here later } switch ((int) this.frame.colour_matrix_index) { case 0: this.frame.KR = 0.2126; this.frame.KB = 0.0722; break; case 1: this.frame.KR = 0.299; this.frame.KB = 0.114; break; case 2: this.frame.KR = 0.25; // FIXME: is this correct ??? this.frame.KB = 0.25; // FIXME: is this correct ??? break; default: // FIXME: do something here later } switch ((int) this.frame.transfer_function_index) { case 0: // TV this.frame.transfer_function = "TV"; break; case 1: // Extended Colour Gamma this.frame.transfer_function = "Extended Gamut"; break; case 2: // Linear this.frame.transfer_function = "Linear"; break; case 3: // D-Cinema this.frame.transfer_function = "DCI Gamma"; break; default: // FIXME: do something here later } } } /** * @param status The status to set. */ private void setStatus(Status status) { this.status = status; } /** * @return FIXME: should also return something */ private void getPicture() { pictureHeader(); init_decode_params(); if (is_inter()) { picturePrediction(); } waveletTransform(); } private void pictureHeader() { long list_length, retired_picture_offset; this.frame.picture_number = ByteIO.read_bytes(this.input, 4); if (is_inter()) { this.frame.ref1_offset = ByteIO.read_sint(this.input); if (num_of_refs() == 2) { this.frame.ref2_offset = ByteIO.read_sint(this.input); } // FIXME: this.frame.ref1 and this.frame.ref2 haven't been set yet } list_length = ByteIO.read_uint(this.input); while (list_length > 0) { retired_picture_offset = ByteIO.read_sint(this.input); // FIXME: delete retired pictures from the picture buffer list_length--; } } private void init_decode_params() { if (is_intra()) { this.frame.intraDefaults(); } if (is_inter()) { this.frame.interDefaults(); if (num_of_refs() == 1) { this.frame.pictureWeightSingleDefaults(); } if (num_of_refs() == 2) { this.frame.pictureWeightDualDefaults(); } } } private void picturePrediction() { long chroma_scale_x = 0; long chroma_scale_y = 0; long value, alpha, beta; boolean non_default_weight_flag; // Block Parameters this.frame.block_parameters_flag = ByteIO.read_bool(this.input); if (this.frame.block_parameters_flag) { this.frame.block_parameters_index = ByteIO.read_uint(this.input); if (this.frame.block_parameters_index != 0) { // TODO: insert stuff from the block parameters table here switch((int) this.frame.block_parameters_index) { case 1: break; case 2: break; case 3: break; case 4: break; default: // FIXME: do something here later } } else { this.frame.luma_xblen = ByteIO.read_uint(this.input); this.frame.luma_yblen = ByteIO.read_uint(this.input); this.frame.luma_xbsep = ByteIO.read_uint(this.input); this.frame.luma_ybsep = ByteIO.read_uint(this.input); if (this.frame.chroma_format.equals("4:4:4")) { chroma_scale_x = 1; chroma_scale_y = 1; } if (this.frame.chroma_format.equals("4:2:2")) { chroma_scale_x = 2; chroma_scale_y = 1; } if (this.frame.chroma_format.equals("4:2:0")) { chroma_scale_x = 2; chroma_scale_y = 2; } this.frame.chroma_xbsep = this.frame.luma_xbsep / chroma_scale_x; this.frame.chroma_ybsep = this.frame.luma_ybsep / chroma_scale_y; alpha = this.frame.luma_xblen / chroma_scale_x; beta = this.frame.chroma_xbsep + 1; value = (alpha > beta) ? alpha : beta; if (value <= (2* this.frame.chroma_xbsep)) { this.frame.chroma_xblen = value; } alpha = this.frame.luma_yblen / chroma_scale_y; beta = this.frame.chroma_ybsep + 1; value = (alpha > beta) ? alpha : beta; if (value <= (2* this.frame.chroma_ybsep)) { this.frame.chroma_yblen = value; } // FIXME: chroma_xblen and chroma_yblen might not be initialized, waiting for Tim's input on this } } // Motion Vector Precision this.frame.motion_vector_precision_flag = ByteIO.read_bool(this.input); if (this.frame.motion_vector_precision_flag) { this.frame.vector_precision = ByteIO.read_uint(this.input); } // Global Motion this.frame.using_global = ByteIO.read_bool(this.input); // this one has to be set on the frame if (this.frame.using_global) { this.frame.global_motion_only = ByteIO.read_bool(this.input); global_motion_parameters(this.frame.global_motion_params_ref1); if (num_of_refs() == 2) { global_motion_parameters(this.frame.global_motion_params_ref2); } } else { this.frame.global_motion_only = false; // FIXME: should I really need to do something here with global_motion_params_refx as the spec says ? // they have already been set to 0 on initialization } // Picture Prediction Mode this.frame.picture_prediction_mode_flag = ByteIO.read_bool(this.input); if (this.frame.picture_prediction_mode_flag) { this.frame.picture_prediction_mode_index = ByteIO.read_uint(this.input); switch ((int) this.frame.picture_prediction_mode_index) { case 0: this.frame.picture_prediction_mode = "Progressive"; break; case 1: this.frame.picture_prediction_mode = "Interlaced TFF"; break; case 2: this.frame.picture_prediction_mode = "Interlaced BFF"; break; default: // FIXME: should do something here } } else { this.frame.picture_prediction_mode = "Progressive"; } // Picture Weights non_default_weight_flag = ByteIO.read_bool(this.input); if (non_default_weight_flag) { this.frame.weight_precision = ByteIO.read_uint(this.input); this.frame.weight_ref1 = ByteIO.read_uint(this.input); if (num_of_refs() == 2) { this.frame.weight_ref2 = ByteIO.read_uint(this.input); } } block_data(); } private void block_data() { } private void global_motion_parameters(long [] ref) { boolean nonzero_pan_tilt_flag, nonzero_zoom_rotation_shear_flag, nonzero_perspective_flag; nonzero_pan_tilt_flag = ByteIO.read_bool(this.input); if (nonzero_pan_tilt_flag) { ref[0] = ByteIO.read_sint(this.input); // Pan ref[1] = ByteIO.read_sint(this.input); // Tilt } else { ref[0] = 0; ref[1] = 0; } nonzero_zoom_rotation_shear_flag = ByteIO.read_bool(this.input); if (nonzero_zoom_rotation_shear_flag) { ref[2] = ByteIO.read_uint(this.input); // ZRS ref[3] = ByteIO.read_sint(this.input); // A11 ref[4] = ByteIO.read_sint(this.input); // A12 ref[5] = ByteIO.read_sint(this.input); // A21 ref[6] = ByteIO.read_sint(this.input); // A22 } else { ref[2] = 0; ref[3] = 1; ref[4] = 0; ref[5] = 0; ref[6] = 1; } nonzero_perspective_flag = ByteIO.read_bool(this.input); if (nonzero_perspective_flag) { ref[7] = ByteIO.read_uint(this.input); // Perspective Exponent ref[8] = ByteIO.read_sint(this.input); // Perspective X ref[9] = ByteIO.read_sint(this.input); // Perspective Y } else { ref[7] = 0; ref[8] = 0; ref[9] = 0; } } private void waveletTransform() { } /** * This method resets the decoder to the sequence defaults * */ private void initializeSequence () { this.frame.video_format = 0; this.frame.picture_buffer.clear(); this.frame.parse_code = 0; this.frame.au_picture_number = 0; this.frame.reference1 = 0; this.frame.reference2 = 0; } /** * * @return true if there are still frames available, false otherwise */ public boolean availableFrame () { if (this.finished) { this.close(); return false; } else return true; } private boolean is_access_unit () { return ((this.frame.parse_code & 0x18) == 0x00); } private boolean is_picture () { return ((this.frame.parse_code & 0x18) == 0x08); } private boolean is_end_of_sequence () { return ((this.frame.parse_code & 0x18) == 0x10); } private boolean is_reference () { return ((this.frame.parse_code & 0x04) == 0x04); } private boolean is_non_reference () { return ((this.frame.parse_code & 0x04) == 0x00); } private long num_of_refs () { return (this.frame.parse_code & 0x03); } private boolean is_intra () { return (num_of_refs() == 0); } private boolean is_inter () { return (num_of_refs() > 0); } } --- NEW FILE: ByteIO.java --- /* * This file is part of Landell. * * Landell is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * Landell 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Landell; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ /** * */ package decoder; import java.io.BufferedInputStream; import java.io.IOException; /** * @author lfelipe * * implements the methos listed on the "Reading Data" section of the Dirac * definition for parsing the input stream */ public class ByteIO { static int bits_left = 0; static byte bit_buffer[] = new byte[1]; public static void reset() { bits_left = 0; bit_buffer[0] = 0; } public static void next_byte (BufferedInputStream input) { try { input.read(bit_buffer); } catch (IOException e) { //FIXME: do something here } } /** * Reads a single bit from the byte stream * * @param input - the byte stream * @return A boolean value depending on the bit read */ public static boolean read_bool (BufferedInputStream input) { boolean value; if (bits_left == 0) { next_byte(input); bits_left = 8; } value = ((bit_buffer[0] & 0x80) > 0)? true : false; bit_buffer[0] <<= 1; bits_left--; return value; } /** * reads and returns the unsigned integer that occupies the next size bytes * of the input stream * @param input - the input stream * @param size - number of bytes * @return unsigned integer */ public static long read_bytes (BufferedInputStream input, int size) { long value = 0; int i; for (i = 0 ; i< size; i++) { value <<= 8; next_byte(input); value = value + bit_buffer[0]; } return value; } /** * reads and returns a variable length unsigned integer * @param input - the input stream * @return unsigned integer */ public static long read_uint (BufferedInputStream input) { long value = 1; while (!read_bool(input)) { value <<= 1; if (read_bool(input)) { value++; } } value--; return value; } /** * reads and returns an signed integer in the variable lenght format * @param input - the input stream * @return signed integer */ public static long read_sint (BufferedInputStream input) { long value; value = read_uint(input); if (read_bool(input) == true) { value = value * (-1); } return value; } } --- NEW FILE: Status.java --- /* * This file is part of Landell. * * Landell is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * Landell 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Landell; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ /** * */ package decoder; /** * @author lfelipe * * Current status of the decoder */ public enum Status { SEQUENCE_START, ACCESS_UNIT_START, FRAME } |