diff --git a/src/input/r_real.cpp b/src/input/r_real.cpp index b542b0469..351e4ffd8 100644 --- a/src/input/r_real.cpp +++ b/src/input/r_real.cpp @@ -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(*track_entry); - - *(static_cast - (&GetChild(video))) = width; - *(static_cast - (&GetChild(video))) = height; - - *(static_cast - (&GetChild(video))) = disp_width; - *(static_cast - (&GetChild(video))) = disp_height; - - rerender_track_headers(); } - dmx->rv_dimensions = true; + KaxTrackEntry *track_entry = PTZR(dmx->ptzr)->get_track_entry(); + KaxTrackVideo &video = GetChild(*track_entry); + + *(static_cast(&GetChild(video))) = width; + *(static_cast(&GetChild(video))) = height; + + *(static_cast(&GetChild(video))) = disp_width; + *(static_cast(&GetChild(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; } diff --git a/src/input/r_real.h b/src/input/r_real.h index abd16819c..11f4602e0 100644 --- a/src/input/r_real.h +++ b/src/input/r_real.h @@ -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