void real_reader_c::parse_headers() { if (rmff_read_headers(file) != RMFF_ERR_OK) return; int ndx; for (ndx = 0; ndx < file->num_tracks; ndx++) { rmff_track_t *track = file->tracks[ndx]; 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; unsigned char *ts_data = track->mdpr_header.type_specific_data; uint32_t ts_size = get_uint32_be(&track->mdpr_header.type_specific_size); 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) {
void mpeg_es_reader_c::read_headers() { try { M2VParser parser; // Let's find the first frame. We need its information like // resolution, MPEG version etc. parser.SetProbeMode(); if (!read_frame(parser, *m_in, 1024 * 1024)) throw mtx::input::header_parsing_x(); m_in->setFilePointer(0); MPEG2SequenceHeader seq_hdr = parser.GetSequenceHeader(); version = parser.GetMPEGVersion(); interlaced = !seq_hdr.progressiveSequence; width = seq_hdr.width; height = seq_hdr.height; frame_rate = seq_hdr.progressiveSequence ? seq_hdr.frameOrFieldRate : seq_hdr.frameOrFieldRate * 2.0f; aspect_ratio = seq_hdr.aspectRatio; if ((0 >= aspect_ratio) || (1 == aspect_ratio)) dwidth = width; else dwidth = (int)(height * aspect_ratio); dheight = height; MPEGChunk *raw_seq_hdr = parser.GetRealSequenceHeader(); if (raw_seq_hdr) { m_ti.m_private_data = (unsigned char *)safememdup(raw_seq_hdr->GetPointer(), raw_seq_hdr->GetSize()); m_ti.m_private_size = raw_seq_hdr->GetSize(); } mxverb(2, boost::format("mpeg_es_reader: version %1% width %2% height %3% FPS %4% AR %5%\n") % version % width % height % frame_rate % aspect_ratio); } catch (mtx::mm_io::exception &) { throw mtx::input::open_x(); } show_demuxer_info(); }
/* The page is the beginning of a new stream. Check the contents for known stream headers. If it is a known stream and the user has requested that it should be extracted then allocate a new packetizer based on the stream type and store the needed data in a new ogm_demuxer_c. */ void ogm_reader_c::handle_new_stream(ogg_page *og) { ogg_stream_state os; ogg_packet op; if (ogg_stream_init(&os, ogg_page_serialno(og))) { mxwarn_fn(m_ti.m_fname, boost::format(Y("ogg_stream_init for stream number %1% failed. Will try to continue and ignore this stream.\n")) % sdemuxers.size()); return; } // Read the first page and get its first packet. ogg_stream_pagein(&os, og); ogg_stream_packetout(&os, &op); ogm_demuxer_c *dmx = nullptr; /* * Check the contents for known stream headers. This one is the * standard Vorbis header. */ if ((7 <= op.bytes) && !strncmp((char *)&op.packet[1], "vorbis", 6)) dmx = new ogm_a_vorbis_demuxer_c(this); else if ((7 <= op.bytes) && !strncmp((char *)&op.packet[1], "theora", 6)) dmx = new ogm_v_theora_demuxer_c(this); else if ((8 <= op.bytes) && !memcmp(&op.packet[1], "kate\0\0\0", 7)) dmx = new ogm_s_kate_demuxer_c(this); // FLAC else if ( ((4 <= op.bytes) && !strncmp(reinterpret_cast<char *>(&op.packet[0]), "fLaC", 4)) || ((5 <= op.bytes) && !strncmp(reinterpret_cast<char *>(&op.packet[1]), "FLAC", 4) && (0x7f == op.packet[0]))) { #if !defined(HAVE_FLAC_FORMAT_H) if (demuxing_requested('a', sdemuxers.size())) mxerror_fn(m_ti.m_fname, Y("mkvmerge has not been compiled with FLAC support but handling of this stream has been requested.\n")); else { dmx = new ogm_demuxer_c(this); dmx->stype = OGM_STREAM_TYPE_A_FLAC; dmx->in_use = true; } #else dmx = new ogm_a_flac_demuxer_c(this, 0x7f == op.packet[0] ? ofm_post_1_1_1 : ofm_pre_1_1_1); #endif } else if ((static_cast<size_t>(op.bytes) >= sizeof(vp8_ogg_header_t)) && (0x4f == op.packet[0]) && (get_uint32_be(&op.packet[1]) == 0x56503830)) dmx = new ogm_v_vp8_demuxer_c(this, op); else if (((*op.packet & PACKET_TYPE_BITS ) == PACKET_TYPE_HEADER) && (op.bytes >= ((int)sizeof(stream_header) + 1))) { // The new stream headers introduced by OggDS (see ogmstreams.h). stream_header *sth = (stream_header *)(op.packet + 1); char buf[5]; buf[4] = 0; if (!strncmp(sth->streamtype, "video", 5)) { memcpy(buf, (char *)sth->subtype, 4); if (mpeg4::p10::is_avc_fourcc(buf) && !hack_engaged(ENGAGE_ALLOW_AVC_IN_VFW_MODE)) dmx = new ogm_v_avc_demuxer_c(this); else dmx = new ogm_v_mscomp_demuxer_c(this); } else if (!strncmp(sth->streamtype, "audio", 5)) { memcpy(buf, (char *)sth->subtype, 4); uint32_t codec_id = strtol(buf, (char **)nullptr, 16); if (0x0001 == codec_id) dmx = new ogm_a_pcm_demuxer_c(this); else if ((0x0050 == codec_id) || (0x0055 == codec_id)) dmx = new ogm_a_mp3_demuxer_c(this); else if (0x2000 == codec_id) dmx = new ogm_a_ac3_demuxer_c(this); else if (0x00ff == codec_id) dmx = new ogm_a_aac_demuxer_c(this); else mxwarn_fn(m_ti.m_fname, boost::format(Y("Unknown audio stream type 0x%|1$04x|. Stream ID %2% will be ignored.\n")) % codec_id % sdemuxers.size()); } else if (!strncmp(sth->streamtype, "text", 4)) dmx = new ogm_s_text_demuxer_c(this); } /* * The old OggDS headers (see MPlayer's source, libmpdemux/demux_ogg.c) * are not supported. */ if (!dmx) dmx = new ogm_demuxer_c(this); std::string type = dmx->get_type(); dmx->serialno = ogg_page_serialno(og); dmx->track_id = sdemuxers.size(); dmx->in_use = (type != "unknown") && demuxing_requested(type[0], dmx->track_id); dmx->packet_data.push_back(memory_cptr(new memory_c((unsigned char *)safememdup(op.packet, op.bytes), op.bytes, true))); memcpy(&dmx->os, &os, sizeof(ogg_stream_state)); sdemuxers.push_back(ogm_demuxer_cptr(dmx)); dmx->initialize(); }
int mpeg4_p2_video_packetizer_c::process_non_native(packet_cptr packet) { extract_config_data(packet); // Add a timecode and a duration if they've been given. if (-1 != packet->timecode) { if (!m_default_duration_forced) m_available_timecodes.push_back(timecode_duration_t(packet->timecode, packet->duration)); else { m_available_timecodes.push_back(timecode_duration_t(m_timecodes_generated * m_htrack_default_duration, m_htrack_default_duration)); ++m_timecodes_generated; } } else if (0.0 == m_fps) mxerror_tid(m_ti.m_fname, m_ti.m_id, Y("Cannot convert non-native MPEG4 video frames into native ones if the source container " "provides neither timecodes nor a number of frames per second.\n")); std::vector<video_frame_t> frames; mpeg4::p2::find_frame_types(packet->data->get_buffer(), packet->data->get_size(), frames, m_config_data); for (auto &frame : frames) { if (!frame.is_coded) { ++m_statistics.m_num_n_vops; int num_surplus_timecodes = static_cast<int>(m_available_timecodes.size()) - static_cast<int>(m_ref_frames.size() + m_b_frames.size()); if (0 < num_surplus_timecodes) { std::deque<timecode_duration_t>::iterator start = m_available_timecodes.begin() + m_ref_frames.size() + m_b_frames.size(); std::deque<timecode_duration_t>::iterator end = start + num_surplus_timecodes; if (0 != (m_ref_frames.size() + m_b_frames.size())) { std::deque<timecode_duration_t>::iterator last = m_available_timecodes.begin() + m_ref_frames.size() + m_b_frames.size() - 1; std::deque<timecode_duration_t>::iterator cur = start; while (cur != end) { last->m_duration = std::max(last->m_duration, static_cast<int64_t>(0)) + std::max(cur->m_duration, static_cast<int64_t>(0)); ++cur; } } m_available_timecodes.erase(start, end); m_statistics.m_num_dropped_timecodes += num_surplus_timecodes; } continue; } if (FRAME_TYPE_I == frame.type) ++m_statistics.m_num_i_frames; else if (FRAME_TYPE_P == frame.type) ++m_statistics.m_num_p_frames; else ++m_statistics.m_num_b_frames; // Maybe we can flush queued frames now. But only if we don't have // a B frame. if (FRAME_TYPE_B != frame.type) flush_frames(false); frame.data = (unsigned char *)safememdup(packet->data->get_buffer() + frame.pos, frame.size); frame.timecode = -1; if (FRAME_TYPE_B == frame.type) m_b_frames.push_back(frame); else m_ref_frames.push_back(frame); } m_previous_timecode = m_available_timecodes.back().m_timecode; return FILE_STATUS_MOREDATA; }