Moved the bit_cursor_c class into its own file. Removed the byte_cursor_c class because its functionality is completely covered by mm_mem_io_c (and it was not used anywhere). Changed mpeg4_p2_find_frame_types to use a mm_mem_io_c instead of a bit_cursor_c because the former is WAY faster and bit-wise access is not needed.

This commit is contained in:
Moritz Bunkus 2005-02-20 18:40:37 +00:00
parent 58d81f2365
commit 19770e79dc
13 changed files with 300 additions and 362 deletions

View File

@ -16,6 +16,7 @@
#include <stdio.h>
#include <string.h>
#include "bit_cursor.h"
#include "common.h"
#include "aac_common.h"
#include "matroska.h"

201
src/common/bit_cursor.h Normal file
View File

@ -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
<niemayer@isg.de> and modified by Moritz Bunkus <moritz@bunkus.org>.
*/
#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

View File

@ -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.

View File

@ -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
*/

View File

@ -11,8 +11,6 @@
definitions used in all programs, helper functions
Written by Moritz Bunkus <moritz@bunkus.org>.
The bit_cursor_c class was originally written by Peter Niemayer
<niemayer@isg.de> and modified by Moritz Bunkus <moritz@bunkus.org>.
*/
#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;

View File

@ -17,6 +17,7 @@
#include <string.h>
#include <stdio.h>
#include "bit_cursor.h"
#include "common.h"
#include "dts_common.h"

View File

@ -18,27 +18,31 @@
#include <string>
#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

View File

@ -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<video_frame_t> &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<video_frame_t>::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()) {

View File

@ -20,6 +20,7 @@
#include <matroska/KaxSegment.h>
#include <matroska/KaxSeekHead.h>
#include "common.h"
#include "commonebml.h"
#include "error.h"
#include "quickparser.h"

View File

@ -21,6 +21,7 @@
#include <FLAC/stream_decoder.h>
#include "bit_cursor.h"
#include "common.h"
#include "flac_common.h"

View File

@ -21,6 +21,7 @@
#include <matroska/KaxTrackVideo.h>
#include "bit_cursor.h"
#include "common.h"
#include "error.h"
#include "p_aac.h"

View File

@ -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<video_frame_t> frames;
vector<video_frame_t>::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);

View File

@ -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,