mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2024-12-24 11:54:01 +00:00
Use the new librmff for low level RealMedia file parsing instead of the built-in parser in r_real.cpp.
This commit is contained in:
parent
e09d3a4463
commit
51ced57715
22
Makefile.in
22
Makefile.in
@ -110,6 +110,7 @@ DEP_KAXCOMMON = src/common/libmtxkaxcommon.a
|
||||
DEP_INPUT = src/input/libmtxinput.a
|
||||
DEP_OUTPUT = src/output/libmtxoutput.a
|
||||
DEP_AVI = $(DEP_AVILIB) $(DEP_AVICLASSES)
|
||||
DEP_RMFF = librmff/librmff.a
|
||||
COMPRESSION_LIBRARIES = $(LZO_LIBS) $(BZ2_LIBS)
|
||||
|
||||
APPLICATIONS = src/mkvmerge src/mkvinfo src/mkvextract src/base64tool
|
||||
@ -144,9 +145,9 @@ install-mans:
|
||||
done
|
||||
|
||||
SYSTEM_INCLUDES = $(AVILIB_INCLUDES) $(AVICLASSES_INCLUDES) \
|
||||
-I. -Isrc -Isrc/common -Isrc/input -Isrc/output
|
||||
-I. -Ilibrmff -Isrc -Isrc/common -Isrc/input -Isrc/output
|
||||
SYSTEM_LIBDIRS = $(AVILIB_LIBDIRS) $(AVICLASSES_LIBDIRS) \
|
||||
-Lsrc/common -Lsrc/input -Lsrc/output
|
||||
-Llibrmff -Lsrc/common -Lsrc/input -Lsrc/output
|
||||
|
||||
RUNAR = $(AR) rcu
|
||||
LINK = $(CXX) $(LDFLAGS) $(LIBDIRS) $(SYSTEM_LIBDIRS)
|
||||
@ -202,6 +203,17 @@ aviclasses/libaviclasses.a: $(libaviclasses_OBJECTS)
|
||||
$(RUNAR) $@ $(libaviclasses_OBJECTS)
|
||||
$(RANLIB) $@
|
||||
|
||||
#
|
||||
# librmff
|
||||
#
|
||||
librmff_SOURCES = $(wildcard librmff/*.c)
|
||||
librmff_OBJECTS := $(patsubst %.c,%.o,$(librmff_SOURCES))
|
||||
|
||||
librmff/librmff.a: $(librmff_OBJECTS)
|
||||
rm -f $@
|
||||
$(RUNAR) $@ $(librmff_OBJECTS)
|
||||
$(RANLIB) $@
|
||||
|
||||
#
|
||||
# src/common
|
||||
#
|
||||
@ -251,11 +263,11 @@ mkvmerge_SOURCES = src/mkvmerge.cpp \
|
||||
src/pr_generic.cpp
|
||||
mkvmerge_OBJECTS := $(patsubst %.cpp,%.o,$(mkvmerge_SOURCES))
|
||||
mkvmerge_DEPENDENCIES += $(DEP_COMMON) \
|
||||
$(DEP_COMP) $(DEP_INPUT) $(DEP_OUTPUT) $(DEP_AVI)
|
||||
$(DEP_COMP) $(DEP_INPUT) $(DEP_OUTPUT) $(DEP_AVI) $(DEP_RMFF)
|
||||
mkvmerge_LDADD = -lmtxinput -lmtxoutput \
|
||||
-lmtxcommon -lmatroska -lebml \
|
||||
-lavi $(AVICLASSES_LIBDIRS) $(AVICLASSES_LIBRARIES) \
|
||||
$(FLAC_LIBS) -lvorbis -logg -lz $(COMPRESSION_LIBRARIES) \
|
||||
-lavi $(AVICLASSES_LIBDIRS) $(AVICLASSES_LIBRARIES) -lrmff \
|
||||
$(FLAC_LIBS) -lvorbis -logg -lz $(COMPRESSION_LIBRARIES) \
|
||||
-lexpat $(ICONV_LIBS)
|
||||
|
||||
mkvinfo_SOURCES = $(wildcard src/mkvinfo*.cpp)
|
||||
|
@ -706,4 +706,4 @@ LDFLAGS="$USER_LDFLAGS @EXTRA_LDFLAGS@"
|
||||
|
||||
AC_SUBST(LDFLAGS)
|
||||
|
||||
AC_OUTPUT(Makefile avilib-0.6.10/Makefile aviclasses/Makefile src/Makefile src/common/Makefile src/input/Makefile src/output/Makefile src/mmg/Makefile)
|
||||
AC_OUTPUT(Makefile avilib-0.6.10/Makefile aviclasses/Makefile librmff/Makefile src/Makefile src/common/Makefile src/input/Makefile src/output/Makefile src/mmg/Makefile)
|
||||
|
@ -42,70 +42,6 @@
|
||||
* http://www.pcisys.net/~melanson/codecs/rmff.htm
|
||||
*/
|
||||
|
||||
// {{{ structs
|
||||
|
||||
typedef struct __attribute__((__packed__)) {
|
||||
uint32_t size;
|
||||
uint32_t fourcc1;
|
||||
uint32_t fourcc2;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint16_t bpp;
|
||||
uint32_t unknown1;
|
||||
uint32_t fps;
|
||||
uint32_t type1;
|
||||
uint32_t type2;
|
||||
} real_video_props_t;
|
||||
|
||||
typedef struct __attribute__((__packed__)) {
|
||||
uint32_t fourcc1; // '.', 'r', 'a', 0xfd
|
||||
uint16_t version1; // 4 or 5
|
||||
uint16_t unknown1; // 00 000
|
||||
uint32_t fourcc2; // .ra4 or .ra5
|
||||
uint32_t unknown2; // ???
|
||||
uint16_t version2; // 4 or 5
|
||||
uint32_t header_size; // == 0x4e
|
||||
uint16_t flavor; // codec flavor id
|
||||
uint32_t coded_frame_size; // coded frame size
|
||||
uint32_t unknown3; // big number
|
||||
uint32_t unknown4; // bigger number
|
||||
uint32_t unknown5; // yet another number
|
||||
uint16_t sub_packet_h;
|
||||
uint16_t frame_size;
|
||||
uint16_t sub_packet_size;
|
||||
uint16_t unknown6; // 00 00
|
||||
uint16_t sample_rate;
|
||||
uint16_t unknown8; // 0
|
||||
uint16_t sample_size;
|
||||
uint16_t channels;
|
||||
} real_audio_v4_props_t;
|
||||
|
||||
typedef struct __attribute__((__packed__)) {
|
||||
uint32_t fourcc1; // '.', 'r', 'a', 0xfd
|
||||
uint16_t version1; // 4 or 5
|
||||
uint16_t unknown1; // 00 000
|
||||
uint32_t fourcc2; // .ra4 or .ra5
|
||||
uint32_t unknown2; // ???
|
||||
uint16_t version2; // 4 or 5
|
||||
uint32_t header_size; // == 0x4e
|
||||
uint16_t flavor; // codec flavor id
|
||||
uint32_t coded_frame_size; // coded frame size
|
||||
uint32_t unknown3; // big number
|
||||
uint32_t unknown4; // bigger number
|
||||
uint32_t unknown5; // yet another number
|
||||
uint16_t sub_packet_h;
|
||||
uint16_t frame_size;
|
||||
uint16_t sub_packet_size;
|
||||
uint16_t unknown6; // 00 00
|
||||
uint8_t unknown7[6]; // 0, srate, 0
|
||||
uint16_t sample_rate;
|
||||
uint16_t unknown8; // 0
|
||||
uint16_t sample_size;
|
||||
uint16_t channels;
|
||||
uint32_t genr; // "genr"
|
||||
uint32_t fourcc3; // fourcc
|
||||
} real_audio_v5_props_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t chunks; // number of chunks
|
||||
uint32_t timecode; // timecode from packet header
|
||||
@ -149,17 +85,16 @@ real_reader_c::real_reader_c(track_info_c *nti)
|
||||
throw (error_c):
|
||||
generic_reader_c(nti) {
|
||||
|
||||
try {
|
||||
io = new mm_io_c(ti->fname, MODE_READ);
|
||||
io->setFilePointer(0, seek_end);
|
||||
file_size = io->getFilePointer();
|
||||
io->setFilePointer(0, seek_beginning);
|
||||
if (!real_reader_c::probe_file(io, file_size))
|
||||
file = rmff_open_file(ti->fname, RMFF_OPEN_MODE_READING);
|
||||
if (file == NULL) {
|
||||
if (rmff_last_error == RMFF_ERR_NOT_RMFF)
|
||||
throw error_c(PFX "Source is not a valid RealMedia file.");
|
||||
|
||||
} catch (exception &ex) {
|
||||
throw error_c(PFX "Could not read the source file.");
|
||||
else
|
||||
throw error_c(PFX "Could not read the source file.");
|
||||
}
|
||||
file->io->seek(file->handle, 0, SEEK_END);
|
||||
file_size = file->io->tell(file->handle);
|
||||
file->io->seek(file->handle, 0, SEEK_SET);
|
||||
|
||||
done = false;
|
||||
|
||||
@ -180,8 +115,6 @@ real_reader_c::~real_reader_c() {
|
||||
real_demuxer_t *demuxer;
|
||||
int i, j;
|
||||
|
||||
delete io;
|
||||
|
||||
for (i = 0; i < demuxers.size(); i++) {
|
||||
demuxer = demuxers[i];
|
||||
if (demuxer->packetizer != NULL)
|
||||
@ -197,6 +130,7 @@ real_reader_c::~real_reader_c() {
|
||||
}
|
||||
demuxers.clear();
|
||||
ti->private_data = NULL;
|
||||
rmff_close_file(file);
|
||||
}
|
||||
|
||||
// }}}
|
||||
@ -205,250 +139,111 @@ real_reader_c::~real_reader_c() {
|
||||
|
||||
void
|
||||
real_reader_c::parse_headers() {
|
||||
uint32_t object_id, i, id, start_time, preroll, size;
|
||||
char *buffer;
|
||||
uint32_t ts_size, ndx, i;
|
||||
unsigned char *ts_data;
|
||||
real_demuxer_t *dmx;
|
||||
real_video_props_t *rvp;
|
||||
real_audio_v4_props_t *ra4p;
|
||||
real_audio_v5_props_t *ra5p;
|
||||
bool mime_type_ok;
|
||||
rmff_track_t *track;
|
||||
|
||||
try {
|
||||
io->skip(4); // object_id = ".RIF"
|
||||
io->skip(4); // header size
|
||||
io->skip(2); // object_version
|
||||
if (rmff_read_headers(file) == RMFF_ERR_OK) {
|
||||
for (ndx = 0; ndx < file->num_tracks; ndx++) {
|
||||
track = &file->tracks[ndx];
|
||||
if ((track->type == RMFF_TRACK_TYPE_UNKNOWN) ||
|
||||
(track->mdpr_header.type_specific_size == 0))
|
||||
continue;
|
||||
if ((track->type == RMFF_TRACK_TYPE_VIDEO) &&
|
||||
!demuxing_requested('v', track->id))
|
||||
continue;
|
||||
if ((track->type == RMFF_TRACK_TYPE_AUDIO) &&
|
||||
!demuxing_requested('a', track->id))
|
||||
continue;
|
||||
if ((track->mdpr_header.mime_type == NULL) ||
|
||||
(!strcmp(track->mdpr_header.mime_type, "audio/x-pn-realaudio") &&
|
||||
!strcmp(track->mdpr_header.mime_type, "video/x-pn-realvideo")))
|
||||
continue;
|
||||
|
||||
io->skip(4); // file_version
|
||||
io->skip(4); // num_headers
|
||||
ts_data = track->mdpr_header.type_specific_data;
|
||||
ts_size = track->mdpr_header.type_specific_size;
|
||||
|
||||
while (1) {
|
||||
object_id = io->read_uint32_be();
|
||||
io->skip(4); // size
|
||||
io->skip(2); // object_version
|
||||
dmx = (real_demuxer_t *)safemalloc(sizeof(real_demuxer_t));
|
||||
memset(dmx, 0, sizeof(real_demuxer_t));
|
||||
dmx->track = track;
|
||||
|
||||
if (object_id == FOURCC('P', 'R', 'O', 'P')) {
|
||||
io->skip(4); // max_bit_rate
|
||||
io->skip(4); // avg_bit_rate
|
||||
io->skip(4); // max_packet_size
|
||||
io->skip(4); // avg_packet_size
|
||||
io->skip(4); // num_packets
|
||||
io->skip(4); // duration
|
||||
io->skip(4); // preroll
|
||||
io->skip(4); // index_offset
|
||||
io->skip(4); // data_offset
|
||||
io->skip(2); // num_streams
|
||||
io->skip(2); // flags
|
||||
if (track->type == RMFF_TRACK_TYPE_VIDEO) {
|
||||
dmx->rvp = (real_video_props_t *)track->mdpr_header.type_specific_data;
|
||||
|
||||
} else if (object_id == FOURCC('C', 'O', 'N', 'T')) {
|
||||
size = io->read_uint16_be(); // title_len
|
||||
if (size > 0) {
|
||||
buffer = (char *)safemalloc(size + 1);
|
||||
memset(buffer, 0, size + 1);
|
||||
if (io->read(buffer, size) != size)
|
||||
throw exception();
|
||||
if (verbose > 1)
|
||||
mxinfo("title: '%s'\n", buffer);
|
||||
safefree(buffer);
|
||||
}
|
||||
memcpy(dmx->fourcc, &dmx->rvp->fourcc2, 4);
|
||||
dmx->fourcc[4] = 0;
|
||||
dmx->width = get_uint16_be(&dmx->rvp->width);
|
||||
dmx->height = get_uint16_be(&dmx->rvp->height);
|
||||
i = get_uint32_be(&dmx->rvp->fps);
|
||||
dmx->fps = (float)((i & 0xffff0000) >> 16) +
|
||||
((float)(i & 0x0000ffff)) / 65536.0;
|
||||
dmx->private_data = (unsigned char *)safememdup(ts_data, ts_size);
|
||||
dmx->private_size = ts_size;
|
||||
|
||||
size = io->read_uint16_be(); // author_len
|
||||
if (size > 0) {
|
||||
buffer = (char *)safemalloc(size + 1);
|
||||
memset(buffer, 0, size + 1);
|
||||
if (io->read(buffer, size) != size)
|
||||
throw exception();
|
||||
if (verbose > 1)
|
||||
mxinfo("author: '%s'\n", buffer);
|
||||
safefree(buffer);
|
||||
}
|
||||
demuxers.push_back(dmx);
|
||||
|
||||
size = io->read_uint16_be(); // copyright_len
|
||||
if (size > 0) {
|
||||
buffer = (char *)safemalloc(size + 1);
|
||||
memset(buffer, 0, size + 1);
|
||||
if (io->read(buffer, size) != size)
|
||||
throw exception();
|
||||
if (verbose > 1)
|
||||
mxinfo("copyright: '%s'\n", buffer);
|
||||
safefree(buffer);
|
||||
}
|
||||
} else if (track->type == RMFF_TRACK_TYPE_AUDIO) {
|
||||
bool ok;
|
||||
|
||||
size = io->read_uint16_be(); // comment_len
|
||||
if (size > 0) {
|
||||
buffer = (char *)safemalloc(size + 1);
|
||||
memset(buffer, 0, size + 1);
|
||||
if (io->read(buffer, size) != size)
|
||||
throw exception();
|
||||
if (verbose > 1)
|
||||
mxinfo("comment: '%s'\n", buffer);
|
||||
safefree(buffer);
|
||||
}
|
||||
ok = true;
|
||||
|
||||
} else if (object_id == FOURCC('M', 'D', 'P', 'R')) {
|
||||
id = io->read_uint16_be();
|
||||
mxverb(2, PFX "MDPR: id %u\n", id);
|
||||
mxverb(2, PFX "MDPR: max_bit_rate %u\n", io->read_uint32_be());
|
||||
mxverb(2, PFX "MDPR: avg_bit_rate %u\n", io->read_uint32_be());
|
||||
mxverb(2, PFX "MDPR: max_packet_size %u\n",
|
||||
io->read_uint32_be());
|
||||
mxverb(2, PFX "MDPR: avg_packet_size %u\n",
|
||||
io->read_uint32_be());
|
||||
start_time = io->read_uint32_be();
|
||||
preroll = io->read_uint32_be();
|
||||
mxverb(2, PFX "MDPR: start_time %u\nreal_reader MDPR: "
|
||||
"preroll %u\nreal_reader MDPR: duration %u\n", start_time,
|
||||
preroll, io->read_uint32_be());
|
||||
dmx->ra4p = (real_audio_v4_props_t *)
|
||||
track->mdpr_header.type_specific_data;
|
||||
dmx->ra5p = (real_audio_v5_props_t *)
|
||||
track->mdpr_header.type_specific_data;
|
||||
dmx->samples_per_second = get_uint16_be(&dmx->ra4p->sample_rate);
|
||||
dmx->channels = get_uint16_be(&dmx->ra4p->channels);
|
||||
dmx->bits_per_sample = get_uint16_be(&dmx->ra4p->sample_size);
|
||||
|
||||
size = io->read_uint8(); // stream_name_size
|
||||
if (size > 0) {
|
||||
buffer = (char *)safemalloc(size + 1);
|
||||
memset(buffer, 0, size + 1);
|
||||
if (io->read(buffer, size) != size)
|
||||
throw exception();
|
||||
mxverb(2, PFX "MDPR stream_name: '%s'\n", buffer);
|
||||
safefree(buffer);
|
||||
}
|
||||
if (get_uint16_be(&dmx->ra4p->version1) == 4) {
|
||||
int slen;
|
||||
unsigned char *p;
|
||||
|
||||
mime_type_ok = false;
|
||||
size = io->read_uint8(); // mime_type_size
|
||||
if (size > 0) {
|
||||
buffer = (char *)safemalloc(size + 1);
|
||||
memset(buffer, 0, size + 1);
|
||||
if (io->read(buffer, size) != size)
|
||||
throw exception();
|
||||
mxverb(2, PFX "MDPR mime_type: '%s'\n", buffer);
|
||||
if (!strcmp(buffer, "audio/x-pn-realaudio") ||
|
||||
!strcmp(buffer, "video/x-pn-realvideo"))
|
||||
mime_type_ok = true;
|
||||
safefree(buffer);
|
||||
}
|
||||
|
||||
size = io->read_uint32_be(); // type_specific_size
|
||||
if (!mime_type_ok)
|
||||
io->skip(size);
|
||||
else if (size > 0) {
|
||||
buffer = (char *)safemalloc(size);
|
||||
if (io->read(buffer, size) != size)
|
||||
throw exception();
|
||||
|
||||
rvp = (real_video_props_t *)buffer;
|
||||
ra4p = (real_audio_v4_props_t *)buffer;
|
||||
ra5p = (real_audio_v5_props_t *)buffer;
|
||||
|
||||
if ((size >= sizeof(real_video_props_t)) &&
|
||||
(get_fourcc(&rvp->fourcc1) == FOURCC('V', 'I', 'D', 'O')) &&
|
||||
demuxing_requested('v', id)) {
|
||||
|
||||
dmx = (real_demuxer_t *)safemalloc(sizeof(real_demuxer_t));
|
||||
memset(dmx, 0, sizeof(real_demuxer_t));
|
||||
dmx->id = id;
|
||||
dmx->start_time = start_time;
|
||||
dmx->preroll = preroll;
|
||||
memcpy(dmx->fourcc, &rvp->fourcc2, 4);
|
||||
p = (unsigned char *)(dmx->ra4p + 1);
|
||||
slen = p[0];
|
||||
p += (slen + 1);
|
||||
slen = p[0];
|
||||
p++;
|
||||
if (slen != 4) {
|
||||
mxwarn(PFX "Couldn't find RealAudio"
|
||||
" FourCC for id %u (description length: %d) Skipping "
|
||||
"track.\n", track->id, slen);
|
||||
ok = false;
|
||||
} else {
|
||||
memcpy(dmx->fourcc, p, 4);
|
||||
dmx->fourcc[4] = 0;
|
||||
dmx->width = get_uint16_be(&rvp->width);
|
||||
dmx->height = get_uint16_be(&rvp->height);
|
||||
dmx->type = 'v';
|
||||
i = get_uint32_be(&rvp->fps);
|
||||
dmx->fps = (float)((i & 0xffff0000) >> 16) +
|
||||
((float)(i & 0x0000ffff)) / 65536.0;
|
||||
dmx->private_data = (unsigned char *)safememdup(buffer, size);
|
||||
dmx->private_size = size;
|
||||
|
||||
demuxers.push_back(dmx);
|
||||
|
||||
} else if ((size >= sizeof(real_audio_v4_props_t)) &&
|
||||
(get_fourcc(&ra4p->fourcc1) ==
|
||||
FOURCC('.', 'r', 'a', 0xfd)) &&
|
||||
demuxing_requested('a', id)) {
|
||||
bool ok;
|
||||
|
||||
ok = true;
|
||||
|
||||
dmx = (real_demuxer_t *)safemalloc(sizeof(real_demuxer_t));
|
||||
memset(dmx, 0, sizeof(real_demuxer_t));
|
||||
dmx->id = id;
|
||||
dmx->start_time = start_time;
|
||||
dmx->preroll = preroll;
|
||||
dmx->type = 'a';
|
||||
if (get_uint16_be(&ra4p->version1) == 4) {
|
||||
int slen;
|
||||
char *p;
|
||||
|
||||
dmx->channels = get_uint16_be(&ra4p->channels);
|
||||
dmx->samples_per_second = get_uint16_be(&ra4p->sample_rate);
|
||||
dmx->bits_per_sample = get_uint16_be(&ra4p->sample_size);
|
||||
p = (char *)(ra4p + 1);
|
||||
slen = (unsigned char)p[0];
|
||||
p += (slen + 1);
|
||||
slen = (unsigned char)p[0];
|
||||
p++;
|
||||
if (slen != 4) {
|
||||
mxwarn(PFX "Couldn't find RealAudio"
|
||||
" FourCC for id %u (description length: %d) Skipping "
|
||||
"track.\n", id, slen);
|
||||
ok = false;
|
||||
} else {
|
||||
memcpy(dmx->fourcc, p, 4);
|
||||
dmx->fourcc[4] = 0;
|
||||
p += 4;
|
||||
if (size > (p - buffer)) {
|
||||
dmx->extra_data_size = size - (p - buffer);
|
||||
dmx->extra_data =
|
||||
(unsigned char *)safememdup(p, dmx->extra_data_size);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
memcpy(dmx->fourcc, &ra5p->fourcc3, 4);
|
||||
dmx->fourcc[4] = 0;
|
||||
dmx->channels = get_uint16_be(&ra5p->channels);
|
||||
dmx->samples_per_second = get_uint16_be(&ra5p->sample_rate);
|
||||
dmx->bits_per_sample = get_uint16_be(&ra5p->sample_size);
|
||||
if (size > (sizeof(real_audio_v5_props_t) + 4)) {
|
||||
dmx->extra_data_size = size - 4 -
|
||||
sizeof(real_audio_v5_props_t);
|
||||
dmx->extra_data =
|
||||
(unsigned char *)safememdup((unsigned char *)ra5p + 4 +
|
||||
sizeof(real_audio_v5_props_t),
|
||||
dmx->extra_data_size);
|
||||
}
|
||||
p += 4;
|
||||
if (ts_size > (p - ts_data)) {
|
||||
dmx->extra_data_size = ts_size - (p - ts_data);
|
||||
dmx->extra_data =
|
||||
(unsigned char *)safememdup(p, dmx->extra_data_size);
|
||||
}
|
||||
mxverb(2, PFX "extra_data_size: %d\n",
|
||||
dmx->extra_data_size);
|
||||
|
||||
if (ok) {
|
||||
dmx->private_data = (unsigned char *)safememdup(buffer, size);
|
||||
dmx->private_size = size;
|
||||
|
||||
demuxers.push_back(dmx);
|
||||
} else
|
||||
free(dmx);
|
||||
}
|
||||
|
||||
safefree(buffer);
|
||||
} else {
|
||||
|
||||
memcpy(dmx->fourcc, &dmx->ra5p->fourcc3, 4);
|
||||
dmx->fourcc[4] = 0;
|
||||
if (ts_size > (sizeof(real_audio_v5_props_t) + 4)) {
|
||||
dmx->extra_data_size = ts_size - 4 - sizeof(real_audio_v5_props_t);
|
||||
dmx->extra_data =
|
||||
(unsigned char *)safememdup((unsigned char *)dmx->ra5p + 4 +
|
||||
sizeof(real_audio_v5_props_t),
|
||||
dmx->extra_data_size);
|
||||
}
|
||||
}
|
||||
mxverb(2, PFX "extra_data_size: %d\n", dmx->extra_data_size);
|
||||
|
||||
} else if (object_id == FOURCC('D', 'A', 'T', 'A')) {
|
||||
num_packets_in_chunk = io->read_uint32_be();
|
||||
num_packets = 0;
|
||||
io->skip(4); // next_data_header
|
||||
if (ok) {
|
||||
dmx->private_data = (unsigned char *)safememdup(ts_data, ts_size);
|
||||
dmx->private_size = ts_size;
|
||||
|
||||
break; // We're finished!
|
||||
|
||||
} else {
|
||||
mxwarn(PFX "Unknown header type (0x%08x, "
|
||||
"%c%c%c%c).\n", object_id, (char)(object_id >> 24),
|
||||
(char)((object_id & 0x00ff0000) >> 16),
|
||||
(char)((object_id & 0x0000ff00) >> 8),
|
||||
(char)(object_id & 0x000000ff));
|
||||
throw exception();
|
||||
demuxers.push_back(dmx);
|
||||
} else
|
||||
free(dmx);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (exception &ex) {
|
||||
throw error_c(PFX "Could not parse the RealMedia headers.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -460,37 +255,34 @@ void
|
||||
real_reader_c::create_packetizer(int64_t tid) {
|
||||
int i;
|
||||
real_demuxer_t *dmx;
|
||||
rmff_track_t *track;
|
||||
bool duplicate_data;
|
||||
|
||||
dmx = NULL;
|
||||
for (i = 0; i < demuxers.size(); i++)
|
||||
if (demuxers[i]->id == tid) {
|
||||
dmx = demuxers[i];
|
||||
break;
|
||||
}
|
||||
dmx = find_demuxer(tid);
|
||||
if (dmx == NULL)
|
||||
return;
|
||||
|
||||
if (dmx->packetizer == NULL) {
|
||||
ti->id = dmx->id;
|
||||
track = dmx->track;
|
||||
ti->id = track->id;
|
||||
ti->private_data = dmx->private_data;
|
||||
ti->private_size = dmx->private_size;
|
||||
duplicate_data = false;
|
||||
|
||||
if (dmx->type == 'v') {
|
||||
if (track->type == RMFF_TRACK_TYPE_VIDEO) {
|
||||
char buffer[20];
|
||||
|
||||
mxprints(buffer, "V_REAL/%s", dmx->fourcc);
|
||||
dmx->packetizer = new video_packetizer_c(this, buffer, dmx->fps,
|
||||
dmx->width, dmx->height,
|
||||
false, ti);
|
||||
dmx->packetizer =
|
||||
new video_packetizer_c(this, buffer, dmx->fps, dmx->width, dmx->height,
|
||||
false, ti);
|
||||
if ((dmx->fourcc[0] != 'R') || (dmx->fourcc[1] != 'V') ||
|
||||
(dmx->fourcc[2] != '4') || (dmx->fourcc[3] != '0'))
|
||||
dmx->rv_dimensions = true;
|
||||
|
||||
if (verbose)
|
||||
mxinfo("+-> Using video output module for stream %u (FourCC: "
|
||||
"%s).\n", dmx->id, dmx->fourcc);
|
||||
"%s).\n", track->id, dmx->fourcc);
|
||||
|
||||
dmx->f_merged = false;
|
||||
dmx->segments = new vector<rv_segment_t>;
|
||||
@ -504,7 +296,7 @@ real_reader_c::create_packetizer(int64_t tid) {
|
||||
new ac3_bs_packetizer_c(this, dmx->samples_per_second, dmx->channels,
|
||||
dmx->bsid, ti);
|
||||
mxverb(1, "+-> Using the AC3 output module for stream "
|
||||
"%u (FourCC: %s).\n", dmx->id, dmx->fourcc);
|
||||
"%u (FourCC: %s).\n", track->id, dmx->fourcc);
|
||||
|
||||
} else if (!strcasecmp(dmx->fourcc, "raac") ||
|
||||
!strcasecmp(dmx->fourcc, "racp")) {
|
||||
@ -535,8 +327,7 @@ real_reader_c::create_packetizer(int64_t tid) {
|
||||
if (profile == -1) {
|
||||
channels = dmx->channels;
|
||||
sample_rate = dmx->samples_per_second;
|
||||
if (!strcasecmp(dmx->fourcc, "racp") ||
|
||||
(dmx->samples_per_second < 44100)) {
|
||||
if (!strcasecmp(dmx->fourcc, "racp") || (sample_rate < 44100)) {
|
||||
output_sample_rate = 2 * sample_rate;
|
||||
sbr = true;
|
||||
}
|
||||
@ -548,7 +339,7 @@ real_reader_c::create_packetizer(int64_t tid) {
|
||||
profile = AAC_PROFILE_SBR;
|
||||
for (i = 0; i < (int)ti->aac_is_sbr->size(); i++)
|
||||
if (((*ti->aac_is_sbr)[i] == -1) ||
|
||||
((*ti->aac_is_sbr)[i] == dmx->id)) {
|
||||
((*ti->aac_is_sbr)[i] == track->id)) {
|
||||
profile = AAC_PROFILE_SBR;
|
||||
break;
|
||||
}
|
||||
@ -562,7 +353,7 @@ real_reader_c::create_packetizer(int64_t tid) {
|
||||
new aac_packetizer_c(this, AAC_ID_MPEG4, profile,
|
||||
sample_rate, channels, ti, false, true);
|
||||
mxverb(1, "+-> Using the AAC output module for stream "
|
||||
"%u (FourCC: %s).\n", dmx->id, dmx->fourcc);
|
||||
"%u (FourCC: %s).\n", track->id, dmx->fourcc);
|
||||
if (profile == AAC_PROFILE_SBR)
|
||||
dmx->packetizer->
|
||||
set_audio_output_sampling_freq(output_sample_rate);
|
||||
@ -572,7 +363,7 @@ real_reader_c::create_packetizer(int64_t tid) {
|
||||
"Therefore you have to specifiy '--aac-is-sbr %u' manually "
|
||||
"for this input file if the file actually contains SBR AAC. "
|
||||
"The file will be muxed in the WRONG way otherwise. Also "
|
||||
"read mkvmerge's documentation.\n", dmx->id);
|
||||
"read mkvmerge's documentation.\n", track->id);
|
||||
duplicate_data = true;
|
||||
|
||||
} else {
|
||||
@ -593,7 +384,7 @@ real_reader_c::create_packetizer(int64_t tid) {
|
||||
|
||||
if (verbose)
|
||||
mxinfo("+-> Using generic audio output module for stream "
|
||||
"%u (FourCC: %s).\n", dmx->id, dmx->fourcc);
|
||||
"%u (FourCC: %s).\n", track->id, dmx->fourcc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -608,7 +399,7 @@ real_reader_c::create_packetizers() {
|
||||
for (i = 0; i < ti->track_order->size(); i++)
|
||||
create_packetizer((*ti->track_order)[i]);
|
||||
for (i = 0; i < demuxers.size(); i++)
|
||||
create_packetizer(demuxers[i]->id);
|
||||
create_packetizer(demuxers[i]->track->id);
|
||||
}
|
||||
|
||||
// }}}
|
||||
@ -620,7 +411,7 @@ real_reader_c::find_demuxer(int id) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < demuxers.size(); i++)
|
||||
if (demuxers[i]->id == id)
|
||||
if (demuxers[i]->track->id == id)
|
||||
return demuxers[i];
|
||||
|
||||
return NULL;
|
||||
@ -634,7 +425,8 @@ real_reader_c::finish() {
|
||||
|
||||
for (i = 0; i < demuxers.size(); i++) {
|
||||
dmx = demuxers[i];
|
||||
if ((dmx->type == 'a') && (dmx->segments != NULL)) {
|
||||
if ((dmx->track->type == RMFF_TRACK_TYPE_AUDIO) &&
|
||||
(dmx->segments != NULL)) {
|
||||
dur = dmx->c_timecode / dmx->c_numpackets;
|
||||
deliver_audio_frames(dmx, dur);
|
||||
}
|
||||
@ -653,82 +445,52 @@ real_reader_c::finish() {
|
||||
|
||||
int
|
||||
real_reader_c::read(generic_packetizer_c *) {
|
||||
uint32_t object_version, length, id, flags, object_id;
|
||||
int size;
|
||||
unsigned char *chunk;
|
||||
real_demuxer_t *dmx;
|
||||
int64_t fpos, timecode;
|
||||
int64_t timecode;
|
||||
rmff_frame_t *frame;
|
||||
|
||||
if (done)
|
||||
return 0;
|
||||
|
||||
try {
|
||||
fpos = io->getFilePointer();
|
||||
if ((file_size - fpos) < 12)
|
||||
return finish();
|
||||
|
||||
if (num_packets >= num_packets_in_chunk) {
|
||||
object_id = io->read_uint32_be();
|
||||
if (object_id == FOURCC('I', 'N', 'D', 'X'))
|
||||
return finish();
|
||||
|
||||
if (object_id == FOURCC('D', 'A', 'T', 'A')) {
|
||||
num_packets_in_chunk = io->read_uint32_be();
|
||||
num_packets = 0;
|
||||
io->skip(4); // next_data_header
|
||||
|
||||
} else
|
||||
return finish();
|
||||
}
|
||||
|
||||
object_version = io->read_uint16_be();
|
||||
length = io->read_uint16_be();
|
||||
id = io->read_uint16_be();
|
||||
timecode = (int64_t)io->read_uint32_be() * 1000000ll;
|
||||
io->skip(1); // reserved
|
||||
flags = io->read_uint8();
|
||||
|
||||
if (length < 12) {
|
||||
mxwarn(PFX "%s: Data packet length is too "
|
||||
"small: %u. Other values: object_version: 0x%04x, id: 0x%04x, "
|
||||
"timecode: %lld, flags: 0x%02x. File position: %lld. Aborting "
|
||||
"this file.\n", ti->fname, length, object_version, id, timecode,
|
||||
flags, fpos);
|
||||
return finish();
|
||||
}
|
||||
|
||||
dmx = find_demuxer(id);
|
||||
if (dmx == NULL) {
|
||||
io->skip(length - 12);
|
||||
return EMOREDATA;
|
||||
}
|
||||
|
||||
mxverb(4, PFX "%u/'%s': timecode = %lldms\n", dmx->id, ti->fname,
|
||||
timecode / 1000000);
|
||||
|
||||
length -= 12;
|
||||
|
||||
chunk = (unsigned char *)safemalloc(length);
|
||||
if (io->read(chunk, length) != length) {
|
||||
safefree(chunk);
|
||||
return finish();
|
||||
}
|
||||
|
||||
num_packets++;
|
||||
|
||||
if (dmx->type == 'v') {
|
||||
assemble_packet(dmx, chunk, length, timecode, (flags & 2) == 2);
|
||||
safefree(chunk);
|
||||
|
||||
} else if (dmx->is_aac)
|
||||
deliver_aac_frames(dmx, chunk, length);
|
||||
|
||||
else
|
||||
queue_audio_frames(dmx, chunk, length, timecode, flags);
|
||||
|
||||
} catch (exception &ex) {
|
||||
size = rmff_get_next_frame_size(file);
|
||||
if (size <= 0) {
|
||||
if (file->num_packets_read < file->num_packets_in_chunk)
|
||||
mxwarn(PFX "%s: File contains fewer frames than expected or is "
|
||||
"corrupt after frame %u.\n", ti->fname, file->num_packets_read);
|
||||
return finish();
|
||||
}
|
||||
|
||||
chunk = (unsigned char *)safemalloc(size);
|
||||
frame = rmff_read_next_frame(file, chunk);
|
||||
if (frame == NULL) {
|
||||
if (file->num_packets_read < file->num_packets_in_chunk)
|
||||
mxwarn(PFX "%s: File contains fewer frames than expected or is "
|
||||
"corrupt after frame %u.\n", ti->fname, file->num_packets_read);
|
||||
safefree(chunk);
|
||||
return finish();
|
||||
}
|
||||
|
||||
timecode = (int64_t)frame->timecode * 1000000ll;
|
||||
dmx = find_demuxer(frame->id);
|
||||
if (dmx == NULL) {
|
||||
rmff_release_frame(frame);
|
||||
return EMOREDATA;
|
||||
}
|
||||
|
||||
if (dmx->track->type == RMFF_TRACK_TYPE_VIDEO) {
|
||||
assemble_packet(dmx, chunk, size, timecode, (frame->flags & 2) == 2);
|
||||
safefree(chunk);
|
||||
|
||||
} else if (dmx->is_aac)
|
||||
deliver_aac_frames(dmx, chunk, size);
|
||||
|
||||
else
|
||||
queue_audio_frames(dmx, chunk, size, timecode, frame->flags);
|
||||
|
||||
rmff_release_frame(frame);
|
||||
|
||||
return EMOREDATA;
|
||||
}
|
||||
|
||||
@ -746,7 +508,7 @@ real_reader_c::queue_one_audio_frame(real_demuxer_t *dmx,
|
||||
dmx->segments->push_back(segment);
|
||||
dmx->c_timecode = timecode;
|
||||
mxverb(2, "enqueueing one for %u/'%s' length %u timecode %llu flags "
|
||||
"0x%08x\n", dmx->id, ti->fname, length, timecode, flags);
|
||||
"0x%08x\n", dmx->track->id, ti->fname, length, timecode, flags);
|
||||
}
|
||||
|
||||
void
|
||||
@ -781,7 +543,7 @@ real_reader_c::deliver_audio_frames(real_demuxer_t *dmx, uint64_t duration) {
|
||||
for (i = 0; i < dmx->segments->size(); i++) {
|
||||
segment = (*dmx->segments)[i];
|
||||
mxverb(2, "delivering audio for %u/'%s' length %llu timecode %llu flags "
|
||||
"0x%08x duration %llu\n", dmx->id, ti->fname, segment.size,
|
||||
"0x%08x duration %llu\n", dmx->track->id, ti->fname, segment.size,
|
||||
dmx->c_timecode, (uint32_t)segment.offset, duration);
|
||||
dmx->packetizer->process(segment.data, segment.size,
|
||||
dmx->c_timecode, duration,
|
||||
@ -802,7 +564,7 @@ real_reader_c::deliver_aac_frames(real_demuxer_t *dmx,
|
||||
|
||||
if (length < 2) {
|
||||
mxwarn(PFX "Short AAC audio packet for track ID %u of "
|
||||
"'%s' (length: %u < 2)\n", dmx->id, ti->fname, length);
|
||||
"'%s' (length: %u < 2)\n", dmx->track->id, ti->fname, length);
|
||||
safefree(chunk);
|
||||
return;
|
||||
}
|
||||
@ -810,7 +572,7 @@ real_reader_c::deliver_aac_frames(real_demuxer_t *dmx,
|
||||
mxverb(2, PFX "num_sub_packets = %u\n", num_sub_packets);
|
||||
if (length < (2 + num_sub_packets * 2)) {
|
||||
mxwarn(PFX "Short AAC audio packet for track ID %u of "
|
||||
"'%s' (length: %u < %u)\n", dmx->id, ti->fname, length,
|
||||
"'%s' (length: %u < %u)\n", dmx->track->id, ti->fname, length,
|
||||
2 + num_sub_packets * 2);
|
||||
safefree(chunk);
|
||||
return;
|
||||
@ -823,7 +585,7 @@ real_reader_c::deliver_aac_frames(real_demuxer_t *dmx,
|
||||
}
|
||||
if (len_check != length) {
|
||||
mxwarn(PFX "Inconsistent AAC audio packet for track ID %u of "
|
||||
"'%s' (length: %u != len_check %u)\n", dmx->id, ti->fname,
|
||||
"'%s' (length: %u != len_check %u)\n", dmx->track->id, ti->fname,
|
||||
length, len_check);
|
||||
safefree(chunk);
|
||||
return;
|
||||
@ -849,11 +611,12 @@ real_reader_c::display_priority() {
|
||||
void
|
||||
real_reader_c::display_progress(bool final) {
|
||||
if (final)
|
||||
mxinfo("progress: %lld/%lld packets (100%%)\r", num_packets_in_chunk,
|
||||
num_packets_in_chunk);
|
||||
mxinfo("progress: %u/%u packets (100%%)\r", file->num_packets_in_chunk,
|
||||
file->num_packets_in_chunk);
|
||||
else
|
||||
mxinfo("progress: %lld/%lld packets (%lld%%)\r", num_packets,
|
||||
num_packets_in_chunk, num_packets * 100 / num_packets_in_chunk);
|
||||
mxinfo("progress: %u/%u packets (%u%%)\r", file->num_packets_read,
|
||||
file->num_packets_in_chunk, file->num_packets_read * 100 /
|
||||
file->num_packets_in_chunk);
|
||||
}
|
||||
|
||||
void
|
||||
@ -867,7 +630,7 @@ real_reader_c::set_headers() {
|
||||
for (i = 0; i < ti->track_order->size(); i++) {
|
||||
d = NULL;
|
||||
for (k = 0; k < demuxers.size(); k++)
|
||||
if (demuxers[k]->id == (*ti->track_order)[i]) {
|
||||
if (demuxers[k]->track->id == (*ti->track_order)[i]) {
|
||||
d = demuxers[k];
|
||||
break;
|
||||
}
|
||||
@ -893,10 +656,11 @@ real_reader_c::identify() {
|
||||
demuxer = demuxers[i];
|
||||
if (!strcasecmp(demuxer->fourcc, "raac") ||
|
||||
!strcasecmp(demuxer->fourcc, "racp"))
|
||||
mxinfo("Track ID %d: audio (AAC)\n", demuxer->id);
|
||||
mxinfo("Track ID %d: audio (AAC)\n", demuxer->track->id);
|
||||
else
|
||||
mxinfo("Track ID %d: %s (%s)\n", demuxer->id,
|
||||
demuxer->type == 'a' ? "audio" : "video", demuxer->fourcc);
|
||||
mxinfo("Track ID %d: %s (%s)\n", demuxer->track->id,
|
||||
demuxer->track->type == RMFF_TRACK_TYPE_AUDIO ? "audio" : "video",
|
||||
demuxer->fourcc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -928,8 +692,9 @@ real_reader_c::deliver_segments(real_demuxer_t *dmx,
|
||||
if (len != total) {
|
||||
mxwarn("\nreal_reader: packet assembly failed. "
|
||||
"Expected packet length was %d but found only %d sub packets "
|
||||
"containing %d bytes. Sub packet number: %lld. Trying to "
|
||||
"continue.\n", len, dmx->segments->size(), total, num_packets);
|
||||
"containing %d bytes. Sub packet number: %u. Trying to "
|
||||
"continue.\n", len, dmx->segments->size(), total,
|
||||
file->num_packets_read);
|
||||
len = 0;
|
||||
for (i = 0; i < dmx->segments->size(); i++) {
|
||||
segment = &(*dmx->segments)[i];
|
||||
@ -1197,13 +962,10 @@ real_reader_c::set_dimensions(real_demuxer_t *dmx,
|
||||
|
||||
void
|
||||
real_reader_c::get_information_from_data() {
|
||||
uint32_t length, id;
|
||||
int i;
|
||||
unsigned char *chunk;
|
||||
real_demuxer_t *dmx;
|
||||
bool information_found;
|
||||
|
||||
io->save_pos();
|
||||
rmff_frame_t *frame;
|
||||
|
||||
information_found = true;
|
||||
for (i = 0; i < demuxers.size(); i++) {
|
||||
@ -1214,50 +976,32 @@ real_reader_c::get_information_from_data() {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
while (!information_found) {
|
||||
io->skip(2);
|
||||
length = io->read_uint16_be();
|
||||
id = io->read_uint16_be();
|
||||
io->skip(4 + 1 + 1);
|
||||
while (!information_found) {
|
||||
frame = rmff_read_next_frame(file, NULL);
|
||||
dmx = find_demuxer(frame->id);
|
||||
|
||||
if (length < 12)
|
||||
die(PFX "Data packet too small.");
|
||||
|
||||
dmx = find_demuxer(id);
|
||||
|
||||
if (dmx == NULL) {
|
||||
io->skip(length - 12);
|
||||
continue;
|
||||
}
|
||||
|
||||
length -= 12;
|
||||
|
||||
chunk = (unsigned char *)safemalloc(length);
|
||||
if (io->read(chunk, length) != length)
|
||||
break;
|
||||
|
||||
num_packets++;
|
||||
|
||||
if (!strcasecmp(dmx->fourcc, "DNET"))
|
||||
dmx->bsid = chunk[4] >> 3;
|
||||
|
||||
safefree(chunk);
|
||||
|
||||
information_found = true;
|
||||
for (i = 0; i < demuxers.size(); i++) {
|
||||
dmx = demuxers[i];
|
||||
if (!strcasecmp(dmx->fourcc, "DNET") && (dmx->bsid == -1))
|
||||
information_found = false;
|
||||
|
||||
}
|
||||
if (dmx == NULL) {
|
||||
rmff_release_frame(frame);
|
||||
continue;
|
||||
}
|
||||
|
||||
io->restore_pos();
|
||||
num_packets = 0;
|
||||
if (!strcasecmp(dmx->fourcc, "DNET"))
|
||||
dmx->bsid = frame->data[4] >> 3;
|
||||
|
||||
} catch (exception &ex) {
|
||||
rmff_release_frame(frame);
|
||||
|
||||
information_found = true;
|
||||
for (i = 0; i < demuxers.size(); i++) {
|
||||
dmx = demuxers[i];
|
||||
if (!strcasecmp(dmx->fourcc, "DNET") && (dmx->bsid == -1))
|
||||
information_found = false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
file->io->seek(file->handle, file->first_data_header_offset + 10,
|
||||
SEEK_SET);
|
||||
file->num_packets_read = 0;
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
@ -27,11 +27,11 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "mm_io.h"
|
||||
#include "pr_generic.h"
|
||||
#include "common.h"
|
||||
#include "error.h"
|
||||
#include "librmff.h"
|
||||
#include "p_video.h"
|
||||
#include "pr_generic.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned char *data;
|
||||
@ -41,18 +41,18 @@ typedef struct {
|
||||
typedef struct {
|
||||
generic_packetizer_c *packetizer;
|
||||
bool headers_set;
|
||||
int id;
|
||||
|
||||
uint32_t start_time, preroll;
|
||||
|
||||
int channels, bits_per_sample, samples_per_second, bsid;
|
||||
rmff_track_t *track;
|
||||
|
||||
int bsid, channels, samples_per_second, bits_per_sample;
|
||||
int width, height;
|
||||
float fps;
|
||||
|
||||
char fourcc[5], type;
|
||||
char fourcc[5];
|
||||
bool is_aac;
|
||||
bool rv_dimensions;
|
||||
float fps;
|
||||
|
||||
real_video_props_t *rvp;
|
||||
real_audio_v4_props_t *ra4p;
|
||||
real_audio_v5_props_t *ra5p;
|
||||
|
||||
unsigned char *private_data, *extra_data;
|
||||
int private_size, extra_data_size;
|
||||
@ -68,9 +68,9 @@ typedef struct {
|
||||
|
||||
class real_reader_c: public generic_reader_c {
|
||||
private:
|
||||
mm_io_c *io;
|
||||
rmff_file_t *file;
|
||||
vector<real_demuxer_t *> demuxers;
|
||||
int64_t file_size, num_packets_in_chunk, num_packets;
|
||||
int64_t file_size;
|
||||
bool done;
|
||||
|
||||
public:
|
||||
|
Loading…
Reference in New Issue
Block a user