/* Reads an OGG page from the stream. Returns 0 if there are no more pages left, EMOREDATA otherwise. */ int ogm_reader_c::read_page(ogg_page *og) { int np, done, nread; unsigned char *buf; done = 0; while (!done) { np = ogg_sync_pageseek(&oy, og); // np == 0 means that there is not enough data for a complete page. if (0 >= np) { // np < 0 is the error case. Should not happen with local OGG files. if (0 > np) mxwarn_fn(m_ti.m_fname, Y("Could not find the next Ogg page. This indicates a damaged Ogg/Ogm file. Will try to continue.\n")); buf = (unsigned char *)ogg_sync_buffer(&oy, BUFFER_SIZE); if (!buf) mxerror_fn(m_ti.m_fname, Y("ogg_sync_buffer failed\n")); if (0 >= (nread = m_in->read(buf, BUFFER_SIZE))) return 0; ogg_sync_wrote(&oy, nread); } else // Alright, we have a page. done = 1; } // Here EMOREDATA actually indicates success - a page has been read. return FILE_STATUS_MOREDATA; }
void mp3_reader_c::read_headers() { try { int pos = find_valid_headers(*m_in, 2 * 1024 * 1024, 5); if (0 > pos) throw mtx::input::header_parsing_x(); m_in->setFilePointer(pos, seek_beginning); m_in->read(m_chunk->get_buffer(), 4); decode_mp3_header(m_chunk->get_buffer(), &m_mp3header); m_in->setFilePointer(pos, seek_beginning); show_demuxer_info(); if ((0 < pos) && verbose) mxwarn_fn(m_ti.m_fname, boost::format(Y("Skipping %1% bytes at the beginning (no valid MP3 header found).\n")) % pos); m_ti.m_id = 0; // ID for this track. } catch (mtx::mm_io::exception &) { throw mtx::input::open_x(); } }
void usf_reader_c::parse_metadata(mtx::xml::document_cptr &doc) { auto attribute = doc->document_element().child("metadata").child("language").attribute("code"); if (attribute && !std::string{attribute.value()}.empty()) { int index = map_to_iso639_2_code(attribute.value()); if (-1 != index) m_default_language = iso639_languages[index].iso639_2_code; else if (!g_identifying) mxwarn_fn(m_ti.m_fname, boost::format(Y("The default language code '%1%' is not a valid ISO639-2 language code and will be ignored.\n")) % attribute.value()); } }
void generic_reader_c::check_track_ids_and_packetizers() { add_available_track_ids(); size_t r; for (r = 0; m_requested_track_ids.size() > r; ++r) { bool found = false; size_t a; for (a = 0; m_available_track_ids.size() > a; ++a) if (m_requested_track_ids[r] == m_available_track_ids[a]) { found = true; break; } if (!found) mxwarn_fn(m_ti.m_fname, boost::format(Y("A track with the ID %1% was requested but not found in the file. The corresponding option will be ignored.\n")) % m_requested_track_ids[r]); } }
void ogm_reader_c::handle_stream_comments() { std::shared_ptr<std::vector<std::string> > comments; std::string title; bool charset_warning_printed = false; charset_converter_cptr cch = charset_converter_c::init(m_ti.m_chapter_charset); size_t i; for (i = 0; i < sdemuxers.size(); i++) { ogm_demuxer_cptr &dmx = sdemuxers[i]; if ((OGM_STREAM_TYPE_A_FLAC == dmx->stype) || (2 > dmx->packet_data.size())) continue; comments = extract_vorbis_comments(dmx->packet_data[1]); if (comments->empty()) continue; std::vector<std::string> chapter_strings; size_t j; for (j = 0; comments->size() > j; j++) { mxverb(2, boost::format("ogm_reader: commment for #%1% for %2%: %3%\n") % j % i % (*comments)[j]); std::vector<std::string> comment = split((*comments)[j], "=", 2); if (comment.size() != 2) continue; if (comment[0] == "LANGUAGE") { int index; index = map_to_iso639_2_code(comment[1].c_str()); if (-1 != index) dmx->language = iso639_languages[index].iso639_2_code; else { std::string lang = comment[1]; int pos1 = lang.find("["); while (0 <= pos1) { int pos2 = lang.find("]", pos1); if (-1 == pos2) pos2 = lang.length() - 1; lang.erase(pos1, pos2 - pos1 + 1); pos1 = lang.find("["); } pos1 = lang.find("("); while (0 <= pos1) { int pos2 = lang.find(")", pos1); if (-1 == pos2) pos2 = lang.length() - 1; lang.erase(pos1, pos2 - pos1 + 1); pos1 = lang.find("("); } index = map_to_iso639_2_code(lang.c_str()); if (-1 != index) dmx->language = iso639_languages[index].iso639_2_code; } } else if (comment[0] == "TITLE") title = comment[1]; else if (balg::starts_with(comment[0], "CHAPTER")) chapter_strings.push_back((*comments)[j]); } bool segment_title_set = false; if (title != "") { title = cch->utf8(title); if (!g_segment_title_set && g_segment_title.empty() && (OGM_STREAM_TYPE_V_MSCOMP == dmx->stype)) { g_segment_title = title; g_segment_title_set = true; segment_title_set = true; } dmx->title = title.c_str(); title = ""; } bool chapters_set = false; if (!chapter_strings.empty() && !m_ti.m_no_chapters) { try { std::shared_ptr<mm_mem_io_c> out(new mm_mem_io_c(nullptr, 0, 1000)); out->write_bom("UTF-8"); for (j = 0; j < chapter_strings.size(); j++) out->puts(cch->utf8(chapter_strings[j]) + std::string("\n")); out->set_file_name(m_ti.m_fname); std::shared_ptr<mm_text_io_c> text_out(new mm_text_io_c(out.get(), false)); m_chapters = parse_chapters(text_out.get(), 0, -1, 0, m_ti.m_chapter_language); chapters_set = true; align_chapter_edition_uids(m_chapters.get()); } catch (...) { } } if ( (segment_title_set || chapters_set) && !charset_warning_printed && (m_ti.m_chapter_charset.empty())) { mxwarn_fn(m_ti.m_fname, Y("This Ogg/OGM file contains chapter or title information. Unfortunately the charset used to store this information in " "the file cannot be identified unambiguously. The program assumes that your system's current charset is appropriate. This can " "be overridden with the '--chapter-charset <charset>' switch.\n")); charset_warning_printed = true; } } }
/* 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(); }