diff --git a/src/common/aac_common.cpp b/src/common/aac_common.cpp index 2dddb72e3..f2c94323c 100644 --- a/src/common/aac_common.cpp +++ b/src/common/aac_common.cpp @@ -16,6 +16,7 @@ #include #include +#include "bit_cursor.h" #include "common.h" #include "aac_common.h" #include "matroska.h" diff --git a/src/common/bit_cursor.h b/src/common/bit_cursor.h new file mode 100644 index 000000000..9458d898b --- /dev/null +++ b/src/common/bit_cursor.h @@ -0,0 +1,201 @@ +/* + mkvmerge -- utility for splicing together matroska files + from component media subtypes + + Distributed under the GPL + see the file COPYING for details + or visit http://www.gnu.org/copyleft/gpl.html + + $Id$ + + A class for file-like access on the bit level + + The bit_cursor_c class was originally written by Peter Niemayer + and modified by Moritz Bunkus . +*/ + +#ifndef __BIT_CURSOR_H +#define __BIT_CURSOR_H + +#include "os.h" + +#include "error.h" + +class MTX_DLL_API bit_cursor_c { +private: + const unsigned char *end_of_data; + const unsigned char *byte_position; + const unsigned char *start_of_data; + unsigned int bits_valid; + + bool out_of_data; + +public: + bit_cursor_c(const unsigned char *data, unsigned int len): + end_of_data(data + len), byte_position(data), start_of_data(data), + bits_valid(8), out_of_data(false) { + if (byte_position >= end_of_data) + out_of_data = true; + } + + bool eof() { + return out_of_data; + } + + bool get_bits(unsigned int n, uint64_t &r) { + // returns false if less bits are available than asked for + r = 0; + + while (n > 0) { + if (byte_position >= end_of_data) { + out_of_data = true; + return false; + } + + unsigned int b = 8; // number of bits to extract from the current byte + if (b > n) + b = n; + if (b > bits_valid) + b = bits_valid; + + unsigned int rshift = bits_valid-b; + + r <<= b; + r |= ((*byte_position) >> rshift) & (0xff >> (8 - b)); + + bits_valid -= b; + if (bits_valid == 0) { + bits_valid = 8; + byte_position += 1; + } + + n -= b; + } + + return true; + } + + bool get_bits(unsigned int n, int64_t &r) { + uint64_t t; + bool b = get_bits(n, t); + r = (int64_t)t; + return b; + } + + bool get_bits(unsigned int n, int &r) { + uint64_t t; + bool b = get_bits(n, t); + r = (int)t; + return b; + } + + bool get_bits(unsigned int n, unsigned int &r) { + uint64_t t; + bool b = get_bits(n, t); + r = (unsigned int)t; + return b; + } + + bool get_bit(bool &r) { + uint64_t t; + bool b = get_bits(1, t); + r = (bool)t; + return b; + } + + bool peek_bits(unsigned int n, uint64_t &r) { + int tmp_bits_valid; + const unsigned char *tmp_byte_position; + // returns false if less bits are available than asked for + r = 0; + tmp_byte_position = byte_position; + tmp_bits_valid = bits_valid; + + while (n > 0) { + if (tmp_byte_position >= end_of_data) + return false; + + unsigned int b = 8; // number of bits to extract from the current byte + if (b > n) + b = n; + if (b > tmp_bits_valid) + b = tmp_bits_valid; + + unsigned int rshift = tmp_bits_valid - b; + + r <<= b; + r |= ((*tmp_byte_position) >> rshift) & (0xff >> (8 - b)); + + tmp_bits_valid -= b; + if (tmp_bits_valid == 0) { + tmp_bits_valid = 8; + tmp_byte_position += 1; + } + + n -= b; + } + + return true; + } + + bool peek_bits(unsigned int n, int64_t &r) { + uint64_t t; + bool b = peek_bits(n, t); + r = (int64_t)t; + return b; + } + + bool peek_bits(unsigned int n, int &r) { + uint64_t t; + bool b = peek_bits(n, t); + r = (int)t; + return b; + } + + bool peek_bits(unsigned int n, unsigned int &r) { + uint64_t t; + bool b = peek_bits(n, t); + r = (unsigned int)t; + return b; + } + + bool peek_bit(bool &r) { + uint64_t t; + bool b = peek_bits(1, t); + r = (bool)t; + return b; + } + + bool byte_align() { + if (out_of_data) + return false; + if (bits_valid == 8) + return true; + bits_valid = 0; + byte_position += 1; + return true; + } + + bool set_bit_position(unsigned int pos) { + if (pos >= ((end_of_data - start_of_data) * 8)) { + byte_position = end_of_data; + out_of_data = true; + return false; + } + + byte_position = start_of_data + (pos / 8); + bits_valid = 8 - (pos % 8); + + return true; + } + + int get_bit_position() { + return (byte_position - start_of_data) * 8 + 8 - bits_valid; + } + + bool skip_bits(unsigned int num) { + return set_bit_position(get_bit_position() + num); + } +}; + +#endif // __BIT_CURSOR_H diff --git a/src/common/chapters.cpp b/src/common/chapters.cpp index 104260bd1..990424063 100644 --- a/src/common/chapters.cpp +++ b/src/common/chapters.cpp @@ -96,7 +96,9 @@ chapter_error(const char *fmt, vsprintf(&new_error[strlen(new_error)], new_fmt.c_str(), ap); strcat(new_error, "\n"); va_end(ap); - throw error_c(new_error, true); + new_fmt = new_error; + safefree(new_error); + throw error_c(new_fmt); } /** \brief Reads the start of a file and checks for OGM style comments. diff --git a/src/common/common.cpp b/src/common/common.cpp index 55e732f85..dbd82eeff 100644 --- a/src/common/common.cpp +++ b/src/common/common.cpp @@ -189,107 +189,6 @@ bitvalue_c::generate_random() { value[i] = (unsigned char)(255.0 * rand() / RAND_MAX); } -// --------------------------------------------------------------------- - -byte_cursor_c::byte_cursor_c(const unsigned char *ndata, - int nsize): - size(nsize), - data(ndata) { - pos = 0; - if (nsize < 0) - throw error_c("wrong usage: nsize < 0"); -} - -unsigned char -byte_cursor_c::get_uint8() { - if ((pos + 1) > size) - throw error_c("end-of-data"); - - pos++; - - return data[pos - 1]; -} - -unsigned short -byte_cursor_c::get_uint16_be() { - unsigned short v; - - if ((pos + 2) > size) - throw error_c("end-of-data"); - - v = ::get_uint16_be(&data[pos]); - pos += 2; - - return v; -} - -unsigned int -byte_cursor_c::get_uint32_be() { - unsigned int v; - - if ((pos + 4) > size) - throw error_c("end-of-data"); - - v = ::get_uint32_be(&data[pos]); - pos += 4; - - return v; -} - -unsigned short -byte_cursor_c::get_uint16_le() { - unsigned short v; - - if ((pos + 2) > size) - throw error_c("end-of-data"); - - v = ::get_uint16_le(&data[pos]); - pos += 2; - - return v; -} - -unsigned int -byte_cursor_c::get_uint32_le() { - unsigned int v; - - if ((pos + 4) > size) - throw error_c("end-of-data"); - - v = ::get_uint32_le(&data[pos]); - pos += 4; - - return v; -} - -void -byte_cursor_c::skip(int n) { - if ((pos + n) > size) - throw error_c("end-of-data"); - - pos += n; -} - -void -byte_cursor_c::get_bytes(unsigned char *dst, - int n) { - if ((pos + n) > size) - throw error_c("end-of-data"); - - memcpy(dst, &data[pos], n); - pos += n; -} - -int -byte_cursor_c::get_pos() { - return pos; -} - -int -byte_cursor_c::get_len() { - return size - pos; -} - /* Control functions */ diff --git a/src/common/common.h b/src/common/common.h index 92b896a5f..0a93ef463 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -11,8 +11,6 @@ definitions used in all programs, helper functions Written by Moritz Bunkus . - The bit_cursor_c class was originally written by Peter Niemayer - and modified by Moritz Bunkus . */ #ifndef __COMMON_H @@ -277,204 +275,6 @@ extern int MTX_DLL_API verbose; #define mxfind2(it, value, cont) \ ((id = std::find((cont).begin(), (cont).end(), value)) != (cont).end()) -class MTX_DLL_API bit_cursor_c { -private: - const unsigned char *end_of_data; - const unsigned char *byte_position; - const unsigned char *start_of_data; - unsigned int bits_valid; - - bool out_of_data; - -public: - bit_cursor_c(const unsigned char *data, unsigned int len): - end_of_data(data + len), byte_position(data), start_of_data(data), - bits_valid(8), out_of_data(false) { - if (byte_position >= end_of_data) - out_of_data = true; - } - - bool eof() { - return out_of_data; - } - - bool get_bits(unsigned int n, uint64_t &r) { - // returns false if less bits are available than asked for - r = 0; - - while (n > 0) { - if (byte_position >= end_of_data) { - out_of_data = true; - return false; - } - - unsigned int b = 8; // number of bits to extract from the current byte - if (b > n) - b = n; - if (b > bits_valid) - b = bits_valid; - - unsigned int rshift = bits_valid-b; - - r <<= b; - r |= ((*byte_position) >> rshift) & (0xff >> (8 - b)); - - bits_valid -= b; - if (bits_valid == 0) { - bits_valid = 8; - byte_position += 1; - } - - n -= b; - } - - return true; - } - - bool get_bits(unsigned int n, int64_t &r) { - uint64_t t; - bool b = get_bits(n, t); - r = (int64_t)t; - return b; - } - - bool get_bits(unsigned int n, int &r) { - uint64_t t; - bool b = get_bits(n, t); - r = (int)t; - return b; - } - - bool get_bits(unsigned int n, unsigned int &r) { - uint64_t t; - bool b = get_bits(n, t); - r = (unsigned int)t; - return b; - } - - bool get_bit(bool &r) { - uint64_t t; - bool b = get_bits(1, t); - r = (bool)t; - return b; - } - - bool peek_bits(unsigned int n, uint64_t &r) { - int tmp_bits_valid; - const unsigned char *tmp_byte_position; - // returns false if less bits are available than asked for - r = 0; - tmp_byte_position = byte_position; - tmp_bits_valid = bits_valid; - - while (n > 0) { - if (tmp_byte_position >= end_of_data) - return false; - - unsigned int b = 8; // number of bits to extract from the current byte - if (b > n) - b = n; - if (b > tmp_bits_valid) - b = tmp_bits_valid; - - unsigned int rshift = tmp_bits_valid - b; - - r <<= b; - r |= ((*tmp_byte_position) >> rshift) & (0xff >> (8 - b)); - - tmp_bits_valid -= b; - if (tmp_bits_valid == 0) { - tmp_bits_valid = 8; - tmp_byte_position += 1; - } - - n -= b; - } - - return true; - } - - bool peek_bits(unsigned int n, int64_t &r) { - uint64_t t; - bool b = peek_bits(n, t); - r = (int64_t)t; - return b; - } - - bool peek_bits(unsigned int n, int &r) { - uint64_t t; - bool b = peek_bits(n, t); - r = (int)t; - return b; - } - - bool peek_bits(unsigned int n, unsigned int &r) { - uint64_t t; - bool b = peek_bits(n, t); - r = (unsigned int)t; - return b; - } - - bool peek_bit(bool &r) { - uint64_t t; - bool b = peek_bits(1, t); - r = (bool)t; - return b; - } - - bool byte_align() { - if (out_of_data) - return false; - if (bits_valid == 8) - return true; - bits_valid = 0; - byte_position += 1; - return true; - } - - bool set_bit_position(unsigned int pos) { - if (pos >= ((end_of_data - start_of_data) * 8)) { - byte_position = end_of_data; - out_of_data = true; - return false; - } - - byte_position = start_of_data + (pos / 8); - bits_valid = 8 - (pos % 8); - - return true; - } - - int get_bit_position() { - return (byte_position - start_of_data) * 8 + 8 - bits_valid; - } - - bool skip_bits(unsigned int num) { - return set_bit_position(get_bit_position() + num); - } -}; - -class MTX_DLL_API byte_cursor_c { -private: - int pos, size; - const unsigned char *data; - -public: - byte_cursor_c(const unsigned char *ndata, int nsize); - - virtual unsigned char get_uint8(); - virtual unsigned short get_uint16_le(); - virtual unsigned int get_uint32_le(); - virtual unsigned short get_uint16_be(); - virtual unsigned int get_uint32_be(); - virtual void get_bytes(unsigned char *dst, int n); - - virtual void skip(int n); - - virtual int get_pos(); - virtual int get_len(); -}; - class MTX_DLL_API bitvalue_c { private: unsigned char *value; diff --git a/src/common/dts_common.cpp b/src/common/dts_common.cpp index 4cfe6e417..054a9c693 100644 --- a/src/common/dts_common.cpp +++ b/src/common/dts_common.cpp @@ -17,6 +17,7 @@ #include #include +#include "bit_cursor.h" #include "common.h" #include "dts_common.h" diff --git a/src/common/error.h b/src/common/error.h index 2359aa17b..7a2b7642e 100644 --- a/src/common/error.h +++ b/src/common/error.h @@ -18,27 +18,31 @@ #include -#include "common.h" - using namespace std; class MTX_DLL_API error_c { private: string error; public: - error_c() { - error = "unknown error"; - }; - error_c(char *nerror, bool freeit = false) { - error = nerror; - if (freeit) - safefree(nerror); - }; - error_c(const char *nerror) { error = nerror; }; - error_c(const string &nerror) { error = nerror; }; - error_c(const error_c &e) { error = e.error; }; - const char *get_error() const { return error.c_str(); }; - operator const char *() const { return error.c_str(); }; + error_c(): + error("unknown error") { + } + + error_c(const char *_error): + error(_error) { + } + + error_c(const string &_error): + error(_error) { + } + + const char *get_error() const { + return error.c_str(); + } + + operator const char *() const { + return error.c_str(); + } }; #endif // __ERROR_H diff --git a/src/common/mpeg4_common.cpp b/src/common/mpeg4_common.cpp index 74d8b23d4..0265c4953 100644 --- a/src/common/mpeg4_common.cpp +++ b/src/common/mpeg4_common.cpp @@ -20,6 +20,7 @@ #include "os.h" +#include "bit_cursor.h" #include "common.h" #include "mm_io.h" #include "mpeg4_common.h" @@ -120,66 +121,75 @@ void mpeg4_p2_find_frame_types(const unsigned char *buffer, int size, vector &frames) { - bit_cursor_c bits(buffer, size); + mm_mem_io_c bytes(buffer, size); uint32_t marker, frame_type; int first_frame_start; bool first_frame; video_frame_t frame; vector::iterator fit; - frame.pos = 0; frames.clear(); + mxverb(3, "\nmpeg4_frames: start search in %d bytes\n", size); + + if (4 > size) + return; + + frame.pos = 0; first_frame = true; first_frame_start = 0; - mxverb(3, "\nmpeg4_frames: start search in %d bytes\n", size); - while (!bits.eof()) { - if (!bits.peek_bits(32, marker)) - break; - if ((marker & 0xffffff00) != 0x00000100) { - bits.skip_bits(8); - continue; + try { + marker = bytes.read_uint32_be(); + while (!bytes.eof()) { + if ((marker & 0xffffff00) != 0x00000100) { + marker <<= 8; + marker |= bytes.read_uint8(); + continue; + } + + mxverb(3, "mpeg4_frames: found start code at %lld\n", + bytes.getFilePointer() - 4); + if (marker == MPEGVIDEO_OBJECT_PLAIN_START_CODE) { + if (0 > first_frame_start) + first_frame_start = bytes.getFilePointer() - 4; + + frame_type = bytes.read_uint8() >> 6; + if (!first_frame) { + frame.size = bytes.getFilePointer() - 5 - frame.pos; + frames.push_back(frame); + frame.pos = bytes.getFilePointer() - 5; + } else { + first_frame = false; + frame.pos = first_frame_start; + } + frame.type = frame_type == 0 ? 'I' : frame_type == 1 ? 'P' : + frame_type == 2 ? 'B' : 'S'; + + } else if (first_frame && + ((MPEGVIDEO_VOS_START_CODE == marker) || + (MPEGVIDEO_VISUAL_OBJECT_START_CODE == marker) || + (0x00000140 > marker))) + first_frame_start = -1; + else + first_frame_start = bytes.getFilePointer() - 4; + + marker = bytes.read_uint32_be(); } - mxverb(3, "mpeg4_frames: found start code at %d\n", - bits.get_bit_position() / 8); - bits.skip_bits(32); - if (marker == MPEGVIDEO_OBJECT_PLAIN_START_CODE) { - if (0 > first_frame_start) - first_frame_start = bits.get_bit_position() / 8 - 4; + if (!first_frame) { + frame.size = size - frame.pos; + frames.push_back(frame); + } - if (!bits.get_bits(2, frame_type)) - break; - if (!first_frame) { - frame.size = (bits.get_bit_position() / 8) - 4 - frame.pos; - frames.push_back(frame); - frame.pos = (bits.get_bit_position() / 8) - 4; - } else { - first_frame = false; - frame.pos = first_frame_start; - } - frame.type = frame_type == 0 ? 'I' : frame_type == 1 ? 'P' : - frame_type == 2 ? 'B' : 'S'; - bits.byte_align(); - - } else if (first_frame && - ((MPEGVIDEO_VOS_START_CODE == marker) || - (MPEGVIDEO_VISUAL_OBJECT_START_CODE == marker) || - (0x00000140 > marker))) - first_frame_start = -1; - else - first_frame_start = bits.get_bit_position() / 8 - 4; + } catch(...) { } - if (!first_frame) { - frame.size = size - frame.pos; - frames.push_back(frame); + if (2 <= verbose) { + mxverb(2, "mpeg4_frames: summary: found %d frames ", frames.size()); + for (fit = frames.begin(); fit < frames.end(); fit++) + mxverb(2, "'%c' (%d at %d) ", fit->type, fit->size, fit->pos); + mxverb(2, "\n"); } - mxverb(2, "mpeg4_frames: summary: found %d frames ", frames.size()); - for (fit = frames.begin(); fit < frames.end(); fit++) - mxverb(2, "'%c' (%d at %d) ", - fit->type, fit->size, fit->pos); - mxverb(2, "\n"); fit = frames.begin(); while (fit < frames.end()) { diff --git a/src/common/quickparser.cpp b/src/common/quickparser.cpp index 5bc86febc..edfea2a66 100644 --- a/src/common/quickparser.cpp +++ b/src/common/quickparser.cpp @@ -20,6 +20,7 @@ #include #include +#include "common.h" #include "commonebml.h" #include "error.h" #include "quickparser.h" diff --git a/src/input/flac_common.cpp b/src/input/flac_common.cpp index ebdb16694..657cb0e1a 100644 --- a/src/input/flac_common.cpp +++ b/src/input/flac_common.cpp @@ -21,6 +21,7 @@ #include +#include "bit_cursor.h" #include "common.h" #include "flac_common.h" diff --git a/src/input/r_real.cpp b/src/input/r_real.cpp index cbd3a33f5..87b10bf8e 100644 --- a/src/input/r_real.cpp +++ b/src/input/r_real.cpp @@ -21,6 +21,7 @@ #include +#include "bit_cursor.h" #include "common.h" #include "error.h" #include "p_aac.h" diff --git a/src/output/p_video.cpp b/src/output/p_video.cpp index b95156d62..06292cf97 100644 --- a/src/output/p_video.cpp +++ b/src/output/p_video.cpp @@ -295,6 +295,8 @@ mpeg1_2_video_packetizer_c::create_private_data() { // ---------------------------------------------------------------- + + mpeg4_p2_video_packetizer_c:: mpeg4_p2_video_packetizer_c(generic_reader_c *_reader, double _fps, @@ -305,7 +307,7 @@ mpeg4_p2_video_packetizer_c(generic_reader_c *_reader, video_packetizer_c(_reader, MKV_V_MPEG4_ASP, _fps, _width, _height, _ti), timecodes_generated(0), aspect_ratio_extracted(false), input_is_native(_input_is_native), - output_is_native(hack_engaged(ENGAGE_NATIVE_MPEG4)) { + output_is_native(hack_engaged(ENGAGE_NATIVE_MPEG4)), csum(0) { if (input_is_native && !output_is_native) mxerror("mkvmerge does not support muxing from native MPEG-4 to " @@ -325,15 +327,28 @@ mpeg4_p2_video_packetizer_c(generic_reader_c *_reader, } } +mpeg4_p2_video_packetizer_c::~mpeg4_p2_video_packetizer_c() { + mxinfo("\nCSUM: %lld\n", csum); +} + int mpeg4_p2_video_packetizer_c::process(memory_c &mem, int64_t old_timecode, int64_t duration, int64_t bref, int64_t fref) { + vector frames; + vector::const_iterator frame; + if (!aspect_ratio_extracted) extract_aspect_ratio(mem.data, mem.size); + mpeg4_p2_find_frame_types(mem.data, mem.size, frames); + foreach(frame, frames) { + csum += frame->type + frame->size; + mxinfo("\nFRAME: type %c size %d\n", frame->type, frame->size); + } + if (input_is_native == output_is_native) return video_packetizer_c::process(mem, old_timecode, duration, bref, fref); diff --git a/src/output/p_video.h b/src/output/p_video.h index 017bea0b7..8bda53c9c 100644 --- a/src/output/p_video.h +++ b/src/output/p_video.h @@ -84,11 +84,13 @@ protected: int64_t timecodes_generated; video_frame_t bref_frame, fref_frame; bool aspect_ratio_extracted, input_is_native, output_is_native; + int64_t csum; public: mpeg4_p2_video_packetizer_c(generic_reader_c *_reader, double _fps, int _width, int _height, bool _input_is_native, track_info_c *_ti); + virtual ~mpeg4_p2_video_packetizer_c(); virtual int process(memory_c &mem, int64_t old_timecode = -1, int64_t duration = -1, int64_t bref = VFT_IFRAME,