Cosmetics

This commit is contained in:
Moritz Bunkus 2008-08-27 12:42:52 +00:00
parent caec02cd0d
commit c7a402e217
2 changed files with 354 additions and 414 deletions

View File

@ -125,7 +125,7 @@ real_reader_c::probe_file(mm_io_c *io,
int64_t size) {
unsigned char data[4];
if (size < 4)
if (4 > size)
return 0;
try {
@ -148,10 +148,9 @@ real_reader_c::real_reader_c(track_info_c &_ti)
throw (error_c):
generic_reader_c(_ti) {
file = rmff_open_file_with_io(ti.fname.c_str(), RMFF_OPEN_MODE_READING,
&mm_io_file_io);
if (file == NULL) {
if (rmff_last_error == RMFF_ERR_NOT_RMFF)
file = rmff_open_file_with_io(ti.fname.c_str(), RMFF_OPEN_MODE_READING, &mm_io_file_io);
if (NULL == file) {
if (RMFF_ERR_NOT_RMFF == rmff_last_error)
throw error_c(PFX "Source is not a valid RealMedia file.");
else
throw error_c(PFX "Could not read the source file.");
@ -185,270 +184,248 @@ real_reader_c::~real_reader_c() {
void
real_reader_c::parse_headers() {
uint32_t ts_size, ndx, i;
unsigned char *ts_data;
rmff_track_t *track;
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) ||
(get_uint32_be(&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;
if (rmff_read_headers(file) != RMFF_ERR_OK)
return;
ts_data = track->mdpr_header.type_specific_data;
ts_size = get_uint32_be(&track->mdpr_header.type_specific_size);
int ndx;
for (ndx = 0; ndx < file->num_tracks; ndx++) {
rmff_track_t *track = file->tracks[ndx];
real_demuxer_cptr dmx(new real_demuxer_t(track));
if ((RMFF_TRACK_TYPE_UNKNOWN == track->type) || (get_uint32_be(&track->mdpr_header.type_specific_size) == 0))
continue;
if ((RMFF_TRACK_TYPE_VIDEO == track->type) && !demuxing_requested('v', track->id))
continue;
if ((RMFF_TRACK_TYPE_AUDIO == track->type) && !demuxing_requested('a', track->id))
continue;
if ((NULL == track->mdpr_header.mime_type)
||
( strcmp(track->mdpr_header.mime_type, "audio/x-pn-realaudio")
&& strcmp(track->mdpr_header.mime_type, "video/x-pn-realvideo")))
continue;
if (track->type == RMFF_TRACK_TYPE_VIDEO) {
dmx->rvp = (real_video_props_t *)track->mdpr_header.type_specific_data;
unsigned char *ts_data = track->mdpr_header.type_specific_data;
uint32_t ts_size = get_uint32_be(&track->mdpr_header.type_specific_size);
memcpy(dmx->fourcc, &dmx->rvp->fourcc2, 4);
real_demuxer_cptr dmx(new real_demuxer_t(track));
if (RMFF_TRACK_TYPE_VIDEO == track->type) {
dmx->rvp = (real_video_props_t *)track->mdpr_header.type_specific_data;
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);
uint32_t 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;
demuxers.push_back(dmx);
} else if (RMFF_TRACK_TYPE_AUDIO == track->type) {
bool ok = true;
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;
int version = get_uint16_be(&dmx->ra4p->version1);
if (3 == version) {
dmx->samples_per_second = 8000;
dmx->channels = 1;
dmx->bits_per_sample = 16;
dmx->extra_data_size = 0;
strcpy(dmx->fourcc, "14_4");
} else if (4 == version) {
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);
unsigned char *p = (unsigned char *)(dmx->ra4p + 1);
int slen = p[0];
p += (slen + 1);
slen = p[0];
p++;
if (4 != slen) {
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;
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);
}
}
} else if (5 == version) {
dmx->samples_per_second = get_uint16_be(&dmx->ra5p->sample_rate);
dmx->channels = get_uint16_be(&dmx->ra5p->channels);
dmx->bits_per_sample = get_uint16_be(&dmx->ra5p->sample_size);
memcpy(dmx->fourcc, &dmx->ra5p->fourcc3, 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;
if ((sizeof(real_audio_v5_props_t) + 4) < ts_size) {
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);
}
} else {
mxwarn(PFX "Only audio header versions 3, 4 and 5 are supported. Track ID %u uses version %d and will be skipped.\n", track->id, version);
ok = false;
}
mxverb(2, PFX "extra_data_size: %d\n", dmx->extra_data_size);
if (ok) {
dmx->private_data = (unsigned char *)safememdup(ts_data, ts_size);
dmx->private_size = ts_size;
demuxers.push_back(dmx);
} else if (track->type == RMFF_TRACK_TYPE_AUDIO) {
bool ok;
int version;
ok = true;
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;
version = get_uint16_be(&dmx->ra4p->version1);
if (3 == version) {
dmx->samples_per_second = 8000;
dmx->channels = 1;
dmx->bits_per_sample = 16;
dmx->extra_data_size = 0;
strcpy(dmx->fourcc, "14_4");
} else if (4 == version) {
int slen;
unsigned char *p;
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);
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;
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);
}
}
} else if (5 == version) {
dmx->samples_per_second = get_uint16_be(&dmx->ra5p->sample_rate);
dmx->channels = get_uint16_be(&dmx->ra5p->channels);
dmx->bits_per_sample = get_uint16_be(&dmx->ra5p->sample_size);
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);
}
} else {
mxwarn(PFX "Only audio header versions 3, 4 and 5 are supported. Track ID %u uses version %d and will be skipped.\n", track->id, version);
ok = false;
}
mxverb(2, PFX "extra_data_size: %d\n", dmx->extra_data_size);
if (ok) {
dmx->private_data = (unsigned char *)safememdup(ts_data, ts_size);
dmx->private_size = ts_size;
demuxers.push_back(dmx);
}
}
}
}
}
void
real_reader_c::create_packetizer(int64_t tid) {
real_demuxer_cptr dmx;
rmff_track_t *track;
real_reader_c::create_video_packetizer(real_demuxer_cptr dmx) {
char buffer[20];
dmx = find_demuxer(tid);
mxprints(buffer, "V_REAL/%s", dmx->fourcc);
dmx->ptzr = add_packetizer(new video_packetizer_c(this, buffer, 0.0, dmx->width, dmx->height, ti));
if (strcmp(dmx->fourcc, "RV40"))
dmx->rv_dimensions = true;
mxinfo(FMT_TID "Using the video output module (FourCC: %s).\n", ti.fname.c_str(), (int64_t)dmx->track->id, dmx->fourcc);
}
void
real_reader_c::create_dnet_audio_packetizer(real_demuxer_cptr dmx) {
dmx->ptzr = add_packetizer(new ac3_bs_packetizer_c(this, dmx->samples_per_second, dmx->channels, dmx->bsid, ti));
mxinfo(FMT_TID "Using the AC3 output module (FourCC: %s).\n", ti.fname.c_str(), (int64_t)dmx->track->id, dmx->fourcc);
}
void
real_reader_c::create_aac_audio_packetizer(real_demuxer_cptr dmx) {
int channels, sample_rate;
int detected_profile;
int64_t tid = dmx->track->id;
int profile = -1;
int output_sample_rate = 0;
bool sbr = false;
bool extra_data_parsed = false;
if (4 < dmx->extra_data_size) {
uint32_t extra_len = get_uint32_be(dmx->extra_data);
mxverb(2, PFX "extra_len: %u\n", extra_len);
if ((4 + extra_len) <= dmx->extra_data_size) {
extra_data_parsed = true;
if (!parse_aac_data(&dmx->extra_data[4 + 1], extra_len - 1, profile, channels, sample_rate, output_sample_rate, sbr))
mxerror(FMT_TID "This AAC track does not contain valid headers. Could not parse the AAC information.\n", ti.fname.c_str(), tid);
mxverb(2, PFX "1. profile: %d, channels: %d, sample_rate: %d, output_sample_rate: %d, sbr: %d\n",
profile, channels, sample_rate, output_sample_rate, (int)sbr);
if (sbr)
profile = AAC_PROFILE_SBR;
}
}
if (-1 == profile) {
channels = dmx->channels;
sample_rate = dmx->samples_per_second;
if (!strcasecmp(dmx->fourcc, "racp") || (44100 > sample_rate)) {
output_sample_rate = 2 * sample_rate;
sbr = true;
}
} else {
dmx->channels = channels;
dmx->samples_per_second = sample_rate;
}
detected_profile = profile;
if (sbr)
profile = AAC_PROFILE_SBR;
if ( (map_has_key(ti.all_aac_is_sbr, tid) && ti.all_aac_is_sbr[tid])
|| (map_has_key(ti.all_aac_is_sbr, -1) && ti.all_aac_is_sbr[-1]))
profile = AAC_PROFILE_SBR;
if ((-1 != detected_profile)
&&
( (map_has_key(ti.all_aac_is_sbr, tid) && !ti.all_aac_is_sbr[tid])
|| (map_has_key(ti.all_aac_is_sbr, -1) && !ti.all_aac_is_sbr[-1])))
profile = detected_profile;
mxverb(2, PFX "2. profile: %d, channels: %d, sample_rate: %d, output_sample_rate: %d, sbr: %d\n", profile, channels, sample_rate, output_sample_rate, (int)sbr);
ti.private_data = NULL;
ti.private_size = 0;
dmx->is_aac = true;
dmx->ptzr = add_packetizer(new aac_packetizer_c(this, AAC_ID_MPEG4, profile, sample_rate, channels, ti, false, true));
mxinfo(FMT_TID "Using the AAC output module (FourCC: %s).\n", ti.fname.c_str(), tid, dmx->fourcc);
if (AAC_PROFILE_SBR == profile)
PTZR(dmx->ptzr)->set_audio_output_sampling_freq(output_sample_rate);
else if (!extra_data_parsed)
mxwarn("RealMedia files may contain HE-AAC / AAC+ / SBR AAC audio. In some cases this can NOT be detected automatically. "
"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", (unsigned int)tid);
// AAC packetizers might need the timecode of the first packet in order
// to fill in stuff. Let's misuse ref_timecode for that.
dmx->ref_timecode = -1;
}
void
real_reader_c::create_audio_packetizer(real_demuxer_cptr dmx) {
if (!strncmp(dmx->fourcc, "dnet", 4))
create_dnet_audio_packetizer(dmx);
else if (!strcasecmp(dmx->fourcc, "raac") || !strcasecmp(dmx->fourcc, "racp"))
create_aac_audio_packetizer(dmx);
else {
if (!strcasecmp(dmx->fourcc, "COOK"))
dmx->cook_audio_fix = true;
dmx->ptzr = add_packetizer(new ra_packetizer_c(this, dmx->samples_per_second, dmx->channels, dmx->bits_per_sample, get_uint32_be(dmx->fourcc),
dmx->private_data, dmx->private_size, ti));
mxinfo(FMT_TID "Using the RealAudio output module (FourCC: %s).\n", ti.fname.c_str(), (int64_t)dmx->track->id, dmx->fourcc);
}
}
void
real_reader_c::create_packetizer(int64_t tid) {
real_demuxer_cptr dmx = find_demuxer(tid);
if (dmx.get() == NULL)
return;
if (dmx->ptzr == -1) {
track = dmx->track;
ti.id = track->id;
ti.private_data = dmx->private_data;
ti.private_size = dmx->private_size;
if (-1 != dmx->ptzr)
return;
if (track->type == RMFF_TRACK_TYPE_VIDEO) {
char buffer[20];
rmff_track_t *track = dmx->track;
ti.id = track->id;
ti.private_data = dmx->private_data;
ti.private_size = dmx->private_size;
mxprints(buffer, "V_REAL/%s", dmx->fourcc);
dmx->ptzr =
add_packetizer(new video_packetizer_c(this, buffer, 0.0,
dmx->width, dmx->height, ti));
if ((dmx->fourcc[0] != 'R') || (dmx->fourcc[1] != 'V') ||
(dmx->fourcc[2] != '4') || (dmx->fourcc[3] != '0'))
dmx->rv_dimensions = true;
mxinfo(FMT_TID "Using the video output module (FourCC: %s).\n",
ti.fname.c_str(), (int64_t)track->id, dmx->fourcc);
} else {
ra_packetizer_c *ptzr;
if (!strncmp(dmx->fourcc, "dnet", 4)) {
dmx->ptzr =
add_packetizer(new ac3_bs_packetizer_c(this, dmx->samples_per_second,
dmx->channels, dmx->bsid,
ti));
mxinfo(FMT_TID "Using the AC3 output module (FourCC: %s).\n",
ti.fname.c_str(), (int64_t)track->id, dmx->fourcc);
} else if (!strcasecmp(dmx->fourcc, "raac") ||
!strcasecmp(dmx->fourcc, "racp")) {
int profile, channels, sample_rate, output_sample_rate;
int detected_profile;
uint32_t extra_len;
bool sbr, extra_data_parsed;
profile = -1;
output_sample_rate = 0;
sbr = false;
extra_data_parsed = false;
if (dmx->extra_data_size > 4) {
extra_len = get_uint32_be(dmx->extra_data);
mxverb(2, PFX "extra_len: %u\n", extra_len);
if (dmx->extra_data_size >= (4 + extra_len)) {
extra_data_parsed = true;
if (!parse_aac_data(&dmx->extra_data[4 + 1], extra_len - 1,
profile, channels, sample_rate,
output_sample_rate, sbr))
mxerror(FMT_TID "This AAC track does not contain valid headers. "
"Could not parse the AAC information.\n",
ti.fname.c_str(), (int64_t)track->id);
mxverb(2, PFX "1. profile: %d, channels: %d, "
"sample_rate: %d, output_sample_rate: %d, sbr: %d\n",
profile, channels, sample_rate, output_sample_rate,
(int)sbr);
if (sbr)
profile = AAC_PROFILE_SBR;
}
}
if (profile == -1) {
channels = dmx->channels;
sample_rate = dmx->samples_per_second;
if (!strcasecmp(dmx->fourcc, "racp") || (sample_rate < 44100)) {
output_sample_rate = 2 * sample_rate;
sbr = true;
}
} else {
dmx->channels = channels;
dmx->samples_per_second = sample_rate;
}
detected_profile = profile;
if (sbr)
profile = AAC_PROFILE_SBR;
if ((map_has_key(ti.all_aac_is_sbr, track->id) &&
ti.all_aac_is_sbr[track->id]) ||
(map_has_key(ti.all_aac_is_sbr, -1) && ti.all_aac_is_sbr[-1]))
profile = AAC_PROFILE_SBR;
if ((-1 != detected_profile) &&
((map_has_key(ti.all_aac_is_sbr, track->id) &&
!ti.all_aac_is_sbr[track->id]) ||
(map_has_key(ti.all_aac_is_sbr, -1) && !ti.all_aac_is_sbr[-1])))
profile = detected_profile;
mxverb(2, PFX "2. profile: %d, channels: %d, sample_rate: "
"%d, output_sample_rate: %d, sbr: %d\n", profile, channels,
sample_rate, output_sample_rate, (int)sbr);
ti.private_data = NULL;
ti.private_size = 0;
dmx->is_aac = true;
dmx->ptzr =
add_packetizer(new aac_packetizer_c(this, AAC_ID_MPEG4, profile,
sample_rate, channels, ti, false,
true));
mxinfo(FMT_TID "Using the AAC output module (FourCC: %s).\n",
ti.fname.c_str(), (int64_t)track->id, dmx->fourcc);
if (profile == AAC_PROFILE_SBR)
PTZR(dmx->ptzr)->set_audio_output_sampling_freq(output_sample_rate);
else if (!extra_data_parsed)
mxwarn("RealMedia files may contain HE-AAC / AAC+ / SBR AAC audio. "
"In some cases this can NOT be detected automatically. "
"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", track->id);
// AAC packetizers might need the timecode of the first packet in order
// to fill in stuff. Let's misuse ref_timecode for that.
dmx->ref_timecode = -1;
} else {
if (!strcasecmp(dmx->fourcc, "COOK"))
dmx->cook_audio_fix = true;
ptzr = new ra_packetizer_c(this, dmx->samples_per_second,
dmx->channels, dmx->bits_per_sample,
(dmx->fourcc[0] << 24) |
(dmx->fourcc[1] << 16) |
(dmx->fourcc[2] << 8) | dmx->fourcc[3],
dmx->private_data, dmx->private_size,
ti);
dmx->ptzr = add_packetizer(ptzr);
mxinfo(FMT_TID "Using the RealAudio output module (FourCC: %s).\n",
ti.fname.c_str(), (int64_t)track->id, dmx->fourcc);
}
}
}
if (RMFF_TRACK_TYPE_VIDEO == track->type)
create_video_packetizer(dmx);
else
create_audio_packetizer(dmx);
}
void
@ -473,17 +450,11 @@ real_reader_c::find_demuxer(int id) {
file_status_e
real_reader_c::finish() {
int i;
int64_t dur;
real_demuxer_cptr dmx;
for (i = 0; i < demuxers.size(); i++) {
dmx = demuxers[i];
if ((NULL != dmx.get()) && (NULL != dmx->track) &&
(dmx->track->type == RMFF_TRACK_TYPE_AUDIO) &&
!dmx->segments.empty()) {
dur = dmx->last_timecode / dmx->num_packets;
deliver_audio_frames(dmx, dur);
}
real_demuxer_cptr dmx = demuxers[i];
if ((NULL != dmx.get()) && (NULL != dmx->track) && (dmx->track->type == RMFF_TRACK_TYPE_AUDIO) && !dmx->segments.empty())
deliver_audio_frames(dmx, dmx->last_timecode / dmx->num_packets);
}
done = true;
@ -496,56 +467,44 @@ real_reader_c::finish() {
file_status_e
real_reader_c::read(generic_packetizer_c *,
bool) {
int size;
unsigned char *chunk;
real_demuxer_cptr dmx;
int64_t timecode;
rmff_frame_t *frame;
if (done)
return FILE_STATUS_DONE;
size = rmff_get_next_frame_size(file);
if (size <= 0) {
int size = rmff_get_next_frame_size(file);
if (0 >= size) {
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.c_str(),
file->num_packets_read);
mxwarn(PFX "%s: File contains fewer frames than expected or is corrupt after frame %u.\n", ti.fname.c_str(), file->num_packets_read);
return finish();
}
chunk = (unsigned char *)safemalloc(size);
unsigned char *chunk = (unsigned char *)safemalloc(size);
memory_c mem(chunk, size, true);
frame = rmff_read_next_frame(file, chunk);
if (frame == NULL) {
rmff_frame_t *frame = rmff_read_next_frame(file, chunk);
if (NULL == frame) {
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.c_str(),
file->num_packets_read);
mxwarn(PFX "%s: File contains fewer frames than expected or is corrupt after frame %u.\n", ti.fname.c_str(), file->num_packets_read);
return finish();
}
timecode = (int64_t)frame->timecode * 1000000ll;
dmx = find_demuxer(frame->id);
int64_t timecode = (int64_t)frame->timecode * 1000000ll;
real_demuxer_cptr dmx = find_demuxer(frame->id);
if ((dmx.get() == NULL) || (-1 == dmx->ptzr)) {
rmff_release_frame(frame);
return FILE_STATUS_MOREDATA;
}
if (dmx->cook_audio_fix && dmx->first_frame &&
((frame->flags & RMFF_FRAME_FLAG_KEYFRAME) !=
RMFF_FRAME_FLAG_KEYFRAME))
if (dmx->cook_audio_fix && dmx->first_frame && ((frame->flags & RMFF_FRAME_FLAG_KEYFRAME) != RMFF_FRAME_FLAG_KEYFRAME))
dmx->force_keyframe_flag = true;
if (dmx->force_keyframe_flag &&
((frame->flags & RMFF_FRAME_FLAG_KEYFRAME) ==
RMFF_FRAME_FLAG_KEYFRAME))
if (dmx->force_keyframe_flag && ((frame->flags & RMFF_FRAME_FLAG_KEYFRAME) == RMFF_FRAME_FLAG_KEYFRAME))
dmx->force_keyframe_flag = false;
if (dmx->force_keyframe_flag)
frame->flags |= RMFF_FRAME_FLAG_KEYFRAME;
if (dmx->track->type == RMFF_TRACK_TYPE_VIDEO)
if (RMFF_TRACK_TYPE_VIDEO == dmx->track->type)
assemble_video_packet(dmx, frame);
else if (dmx->is_aac) {
@ -575,13 +534,13 @@ real_reader_c::queue_one_audio_frame(real_demuxer_cptr dmx,
uint32_t flags) {
rv_segment_cptr segment(new rv_segment_t);
segment->data = memory_cptr(new memory_c(mem));
segment->data = memory_cptr(new memory_c(mem));
segment->flags = flags;
dmx->segments.push_back(segment);
dmx->last_timecode = timecode;
mxverb(2, "enqueueing one for %u/'%s' length %u timecode " LLU " flags "
"0x%08x\n", dmx->track->id, ti.fname.c_str(), mem.get_size(),
timecode, flags);
mxverb(2, "enqueueing one for %u/'%s' length %u timecode " LLU " flags 0x%08x\n", dmx->track->id, ti.fname.c_str(), mem.get_size(), timecode, flags);
}
void
@ -597,8 +556,8 @@ real_reader_c::queue_audio_frames(real_demuxer_cptr dmx,
}
// This timecode is different. So let's push the packets out.
deliver_audio_frames(dmx, (timecode - dmx->last_timecode) /
dmx->segments.size());
deliver_audio_frames(dmx, (timecode - dmx->last_timecode) / dmx->segments.size());
// Enqueue this packet.
queue_one_audio_frame(dmx, mem, timecode, flags);
}
@ -607,26 +566,21 @@ void
real_reader_c::deliver_audio_frames(real_demuxer_cptr dmx,
uint64_t duration) {
uint32_t i;
rv_segment_cptr segment;
if (dmx->segments.empty() || (-1 == dmx->ptzr))
return;
for (i = 0; i < dmx->segments.size(); i++) {
segment = dmx->segments[i];
mxverb(2, "delivering audio for %u/'%s' length %d timecode " LLU " flags "
"0x%08x duration " LLU "\n", dmx->track->id, ti.fname.c_str(),
segment->data->get_size(), dmx->last_timecode,
(uint32_t)segment->flags, duration);
PTZR(dmx->ptzr)->process(new packet_t(segment->data,
dmx->last_timecode, duration,
(segment->flags &
RMFF_FRAME_FLAG_KEYFRAME) ==
RMFF_FRAME_FLAG_KEYFRAME ? -1 :
dmx->ref_timecode));
rv_segment_cptr segment = dmx->segments[i];
mxverb(2, "delivering audio for %u/'%s' length %d timecode " LLU " flags 0x%08x duration " LLU "\n", dmx->track->id, ti.fname.c_str(),
segment->data->get_size(), dmx->last_timecode, (uint32_t)segment->flags, duration);
PTZR(dmx->ptzr)->process(new packet_t(segment->data, dmx->last_timecode, duration,
(segment->flags & RMFF_FRAME_FLAG_KEYFRAME) == RMFF_FRAME_FLAG_KEYFRAME ? -1 : dmx->ref_timecode));
if ((segment->flags & 2) == 2)
dmx->ref_timecode = dmx->last_timecode;
}
dmx->num_packets += dmx->segments.size();
dmx->segments.clear();
}
@ -634,43 +588,37 @@ real_reader_c::deliver_audio_frames(real_demuxer_cptr dmx,
void
real_reader_c::deliver_aac_frames(real_demuxer_cptr dmx,
memory_c &mem) {
uint32_t num_sub_packets, data_idx, i, sub_length, len_check;
uint32_t length;
unsigned char *chunk;
unsigned char *chunk = mem.get();
int length = mem.get_size();
if (2 > length) {
mxwarn(PFX "Short AAC audio packet for track ID %u of '%s' (length: %u < 2)\n", dmx->track->id, ti.fname.c_str(), length);
return;
}
chunk = mem.get();
length = mem.get_size();
if (length < 2) {
mxwarn(PFX "Short AAC audio packet for track ID %u of "
"'%s' (length: %u < 2)\n", dmx->track->id, ti.fname.c_str(),
length);
return;
}
num_sub_packets = chunk[1] >> 4;
int num_sub_packets = chunk[1] >> 4;
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->track->id, ti.fname.c_str(),
length, 2 + num_sub_packets * 2);
if ((2 + num_sub_packets * 2) > length) {
mxwarn(PFX "Short AAC audio packet for track ID %u of '%s' (length: %u < %u)\n", dmx->track->id, ti.fname.c_str(), length, 2 + num_sub_packets * 2);
return;
}
len_check = 2 + num_sub_packets * 2;
int i, len_check = 2 + num_sub_packets * 2;
for (i = 0; i < num_sub_packets; i++) {
sub_length = get_uint16_be(&chunk[2 + i * 2]);
int sub_length = get_uint16_be(&chunk[2 + i * 2]);
len_check += sub_length;
mxverb(2, PFX "%u: length %u\n", i, sub_length);
len_check += sub_length;
}
if (len_check != length) {
mxwarn(PFX "Inconsistent AAC audio packet for track ID %u of "
"'%s' (length: %u != len_check %u)\n", dmx->track->id,
ti.fname.c_str(), length, len_check);
mxwarn(PFX "Inconsistent AAC audio packet for track ID %u of '%s' (length: %u != len_check %u)\n", dmx->track->id, ti.fname.c_str(), length, len_check);
return;
}
data_idx = 2 + num_sub_packets * 2;
int data_idx = 2 + num_sub_packets * 2;
for (i = 0; i < num_sub_packets; i++) {
sub_length = get_uint16_be(&chunk[2 + i * 2]);
PTZR(dmx->ptzr)->process(new packet_t(new memory_c(&chunk[data_idx],
sub_length, false)));
int sub_length = get_uint16_be(&chunk[2 + i * 2]);
PTZR(dmx->ptzr)->process(new packet_t(new memory_c(&chunk[data_idx], sub_length, false)));
data_idx += sub_length;
}
}
@ -682,20 +630,18 @@ real_reader_c::get_progress() {
void
real_reader_c::identify() {
int i;
real_demuxer_cptr demuxer;
string type, codec;
id_result_container("RealMedia");
int i;
for (i = 0; i < demuxers.size(); i++) {
demuxer = demuxers[i];
real_demuxer_cptr demuxer = demuxers[i];
string type, codec;
if (!strcasecmp(demuxer->fourcc, "raac") || !strcasecmp(demuxer->fourcc, "racp")) {
type = ID_RESULT_TRACK_AUDIO;
codec = "AAC";
} else {
type = demuxer->track->type == RMFF_TRACK_TYPE_AUDIO ? ID_RESULT_TRACK_AUDIO : ID_RESULT_TRACK_VIDEO;
type = RMFF_TRACK_TYPE_AUDIO == demuxer->track->type ? ID_RESULT_TRACK_AUDIO : ID_RESULT_TRACK_VIDEO;
codec = demuxer->fourcc;
}
@ -706,26 +652,21 @@ real_reader_c::identify() {
void
real_reader_c::assemble_video_packet(real_demuxer_cptr dmx,
rmff_frame_t *frame) {
int result;
rmff_frame_t *assembled;
result = rmff_assemble_packed_video_frame(dmx->track, frame);
if (result < 0) {
mxwarn(PFX "Video packet assembly failed. Error code: %d (%s)\n",
rmff_last_error, rmff_last_error_msg);
int result = rmff_assemble_packed_video_frame(dmx->track, frame);
if (0 > result) {
mxwarn(PFX "Video packet assembly failed. Error code: %d (%s)\n", rmff_last_error, rmff_last_error_msg);
return;
}
assembled = rmff_get_packed_video_frame(dmx->track);
while (assembled != NULL) {
rmff_frame_t *assembled = rmff_get_packed_video_frame(dmx->track);
while (NULL != assembled) {
if (!dmx->rv_dimensions)
set_dimensions(dmx, assembled->data, assembled->size);
packet_t *packet =
new packet_t(new memory_c(assembled->data, assembled->size, true),
(int64_t)assembled->timecode * 1000000, 0,
(assembled->flags & RMFF_FRAME_FLAG_KEYFRAME) ==
RMFF_FRAME_FLAG_KEYFRAME ? VFT_IFRAME :
VFT_PFRAMEAUTOMATIC, VFT_NOBFRAME);
packet_t *packet = new packet_t(new memory_c(assembled->data, assembled->size, true), (int64_t)assembled->timecode * 1000000, 0,
(assembled->flags & RMFF_FRAME_FLAG_KEYFRAME) == RMFF_FRAME_FLAG_KEYFRAME ? VFT_IFRAME : VFT_PFRAMEAUTOMATIC, VFT_NOBFRAME);
PTZR(dmx->ptzr)->process(packet);
assembled->allocated_by_rmff = 0;
rmff_release_frame(assembled);
assembled = rmff_get_packed_video_frame(dmx->track);
@ -737,40 +678,40 @@ real_reader_c::get_rv_dimensions(unsigned char *buf,
int size,
uint32_t &width,
uint32_t &height) {
const uint32_t cw[8] = {160, 176, 240, 320, 352, 640, 704, 0};
const uint32_t ch1[8] = {120, 132, 144, 240, 288, 480, 0, 0};
const uint32_t ch2[4] = {180, 360, 576, 0};
uint32_t w, h, c, v;
static const uint32_t cw[8] = { 160, 176, 240, 320, 352, 640, 704, 0 };
static const uint32_t ch1[8] = { 120, 132, 144, 240, 288, 480, 0, 0 };
static const uint32_t ch2[4] = { 180, 360, 576, 0 };
bit_cursor_c bc(buf, size);
try {
bc.skip_bits(13);
bc.skip_bits(13);
v = bc.get_bits(3);
int v = bc.get_bits(3);
w = cw[v];
if (w == 0) {
int w = cw[v];
if (0 == w) {
int c;
do {
c = bc.get_bits(8);
w += (c << 2);
} while (c == 255);
}
c = bc.get_bits(3);
h = ch1[c];
if (h == 0) {
int c = bc.get_bits(3);
int h = ch1[c];
if (0 == h) {
v = bc.get_bits(1);
c = ((c << 1) | v) & 3;
h = ch2[c];
if (h == 0) {
if (0 == h) {
do {
c = bc.get_bits(8);
c = bc.get_bits(8);
h += (c << 2);
} while (c == 255);
}
}
width = w;
width = w;
height = h;
return true;
@ -784,88 +725,82 @@ void
real_reader_c::set_dimensions(real_demuxer_cptr dmx,
unsigned char *buffer,
int size) {
uint32_t width, height, disp_width, disp_height;
unsigned char *ptr;
KaxTrackEntry *track_entry;
unsigned char *ptr = buffer;
ptr += 1 + 2 * 4 * (*ptr + 1);
ptr = buffer;
ptr += 1 + 2 * 4 * (*ptr + 1);
if ((ptr + 10) >= (buffer + size))
return;
buffer = ptr;
if (get_rv_dimensions(buffer, size, width, height)) {
if ((dmx->width != width) || (dmx->height != height)) {
if (!ti.aspect_ratio_given && !ti.display_dimensions_given) {
disp_width = dmx->width;
disp_height = dmx->height;
uint32_t width, height;
if (!get_rv_dimensions(buffer, size, width, height))
return;
dmx->width = width;
dmx->height = height;
if ((dmx->width != width) || (dmx->height != height)) {
uint32_t disp_width, disp_height;
} else if (ti.display_dimensions_given) {
disp_width = ti.display_width;
disp_height = ti.display_height;
if (!ti.aspect_ratio_given && !ti.display_dimensions_given) {
disp_width = dmx->width;
disp_height = dmx->height;
dmx->width = width;
dmx->height = height;
dmx->width = width;
dmx->height = height;
} else { // ti.aspect_ratio_given == true
dmx->width = width;
dmx->height = height;
} else if (ti.display_dimensions_given) {
disp_width = ti.display_width;
disp_height = ti.display_height;
if (ti.aspect_ratio > ((float)width / (float)height)) {
disp_width = (uint32_t)(height * ti.aspect_ratio);
disp_height = height;
dmx->width = width;
dmx->height = height;
} else {
disp_width = width;
disp_height = (uint32_t)(width / ti.aspect_ratio);
}
} else { // ti.aspect_ratio_given == true
dmx->width = width;
dmx->height = height;
if (((float)width / (float)height) < ti.aspect_ratio) {
disp_width = (uint32_t)(height * ti.aspect_ratio);
disp_height = height;
} else {
disp_width = width;
disp_height = (uint32_t)(width / ti.aspect_ratio);
}
track_entry = PTZR(dmx->ptzr)->get_track_entry();
KaxTrackVideo &video = GetChild<KaxTrackVideo>(*track_entry);
*(static_cast<EbmlUInteger *>
(&GetChild<KaxVideoPixelWidth>(video))) = width;
*(static_cast<EbmlUInteger *>
(&GetChild<KaxVideoPixelHeight>(video))) = height;
*(static_cast<EbmlUInteger *>
(&GetChild<KaxVideoDisplayWidth>(video))) = disp_width;
*(static_cast<EbmlUInteger *>
(&GetChild<KaxVideoDisplayHeight>(video))) = disp_height;
rerender_track_headers();
}
dmx->rv_dimensions = true;
KaxTrackEntry *track_entry = PTZR(dmx->ptzr)->get_track_entry();
KaxTrackVideo &video = GetChild<KaxTrackVideo>(*track_entry);
*(static_cast<EbmlUInteger *>(&GetChild<KaxVideoPixelWidth>(video))) = width;
*(static_cast<EbmlUInteger *>(&GetChild<KaxVideoPixelHeight>(video))) = height;
*(static_cast<EbmlUInteger *>(&GetChild<KaxVideoDisplayWidth>(video))) = disp_width;
*(static_cast<EbmlUInteger *>(&GetChild<KaxVideoDisplayHeight>(video))) = disp_height;
rerender_track_headers();
}
dmx->rv_dimensions = true;
}
void
real_reader_c::get_information_from_data() {
int i;
real_demuxer_cptr dmx;
bool information_found;
rmff_frame_t *frame;
int64_t old_pos;
int64_t old_pos = file->io->tell(file->handle);
bool information_found = true;
old_pos = file->io->tell(file->handle);
information_found = true;
int i;
for (i = 0; i < demuxers.size(); i++) {
dmx = demuxers[i];
real_demuxer_cptr dmx = demuxers[i];
if (!strcasecmp(dmx->fourcc, "DNET")) {
dmx->bsid = -1;
dmx->bsid = -1;
information_found = false;
}
}
while (!information_found) {
frame = rmff_read_next_frame(file, NULL);
dmx = find_demuxer(frame->id);
rmff_frame_t *frame = rmff_read_next_frame(file, NULL);
real_demuxer_cptr dmx = find_demuxer(frame->id);
if (dmx.get() == NULL) {
rmff_release_frame(frame);
@ -880,7 +815,7 @@ real_reader_c::get_information_from_data() {
information_found = true;
for (i = 0; i < demuxers.size(); i++) {
dmx = demuxers[i];
if (!strcasecmp(dmx->fourcc, "DNET") && (dmx->bsid == -1))
if (!strcasecmp(dmx->fourcc, "DNET") && (-1 == dmx->bsid))
information_found = false;
}

View File

@ -125,6 +125,11 @@ protected:
virtual void queue_audio_frames(real_demuxer_cptr dmx, memory_c &mem, uint64_t timecode, uint32_t flags);
virtual void queue_one_audio_frame(real_demuxer_cptr dmx, memory_c &mem, uint64_t timecode, uint32_t flags);
virtual void deliver_audio_frames(real_demuxer_cptr dmx, uint64_t duration);
virtual void create_audio_packetizer(real_demuxer_cptr dmx);
virtual void create_aac_audio_packetizer(real_demuxer_cptr dmx);
virtual void create_dnet_audio_packetizer(real_demuxer_cptr dmx);
virtual void create_video_packetizer(real_demuxer_cptr dmx);
};
#endif // __R_REAL_H