void xtr_hevc_c::create_file(xtr_base_c *master, KaxTrackEntry &track) { xtr_base_c::create_file(master, track); auto priv = FindChild<KaxCodecPrivate>(&track); if (!priv) mxerror(boost::format(Y("Track %1% with the CodecID '%2%' is missing the \"codec private\" element and cannot be extracted.\n")) % m_tid % m_codec_id); auto mpriv = decode_codec_private(priv); if (mpriv->get_size() < 23) mxerror(boost::format(Y("Track %1% CodecPrivate is too small.\n")) % m_tid); auto buf = mpriv->get_buffer(); m_nal_size_size = 1 + (buf[21] & 3); // Parameter sets in this order: vps, sps, pps, sei auto num_parameter_sets = static_cast<unsigned int>(buf[22]); auto pos = static_cast<size_t>(23); while (num_parameter_sets && (mpriv->get_size() > (pos + 3))) { auto nal_unit_count = get_uint16_be(&buf[pos + 1]); pos += 3; while (nal_unit_count && (mpriv->get_size() > pos)) { if (!write_nal(buf, pos, mpriv->get_size(), 2)) return; --nal_unit_count; --num_parameter_sets; } } }
void xtr_avc_c::create_file(xtr_base_c *master, KaxTrackEntry &track) { xtr_base_c::create_file(master, track); KaxCodecPrivate *priv = FindChild<KaxCodecPrivate>(&track); if (!priv) mxerror(boost::format(Y("Track %1% with the CodecID '%2%' is missing the \"codec private\" element and cannot be extracted.\n")) % m_tid % m_codec_id); memory_cptr mpriv = decode_codec_private(priv); if (mpriv->get_size() < 6) mxerror(boost::format(Y("Track %1% CodecPrivate is too small.\n")) % m_tid); binary *buf = mpriv->get_buffer(); m_nal_size_size = 1 + (buf[4] & 3); size_t pos = 6; unsigned int numsps = buf[5] & 0x1f; size_t i; for (i = 0; (i < numsps) && (mpriv->get_size() > pos); ++i) if (!write_nal(buf, pos, mpriv->get_size(), 2)) break; if (mpriv->get_size() <= pos) return; unsigned int numpps = buf[pos++]; for (i = 0; (i < numpps) && (mpriv->get_size() > pos); ++i) write_nal(buf, pos, mpriv->get_size(), 2); }
void xtr_wavpack4_c::create_file(xtr_base_c *master, KaxTrackEntry &track) { memory_cptr mpriv; init_content_decoder(track); KaxCodecPrivate *priv = FindChild<KaxCodecPrivate>(&track); if (priv) mpriv = decode_codec_private(priv); if (!priv || (2 > mpriv->get_size())) mxerror(boost::format(Y("Track %1% with the CodecID '%2%' is missing the \"codec private\" element and cannot be extracted.\n")) % m_tid % m_codec_id); memcpy(m_version, mpriv->get_buffer(), 2); xtr_base_c::create_file(master, track); m_channels = kt_get_a_channels(track); if ((0 != kt_get_max_blockadd_id(track)) && (0 != m_extract_blockadd_level)) { std::string corr_name = m_file_name; size_t pos = corr_name.rfind('.'); if ((std::string::npos != pos) && (0 != pos)) corr_name.erase(pos + 1); corr_name += "wvc"; try { m_corr_out = mm_write_buffer_io_c::open(corr_name, 5 * 1024 * 1024); } catch (mtx::mm_io::exception &ex) { mxerror(boost::format(Y("The file '%1%' could not be opened for writing: %2%.\n")) % corr_name % ex); } } }
void xtr_mpeg1_2_video_c::create_file(xtr_base_c *master, KaxTrackEntry &track) { xtr_base_c::create_file(master, track); KaxCodecPrivate *priv = FindChild<KaxCodecPrivate>(&track); if (priv) m_seq_hdr = decode_codec_private(priv); }
void xtr_flac_c::create_file(xtr_base_c *_master, KaxTrackEntry &track) { KaxCodecPrivate *priv = FindChild<KaxCodecPrivate>(&track); if (!priv) mxerror(boost::format(Y("Track %1% with the CodecID '%2%' is missing the \"codec private\" element and cannot be extracted.\n")) % m_tid % m_codec_id); xtr_base_c::create_file(_master, track); memory_cptr mpriv = decode_codec_private(priv); m_out->write(mpriv); }
void xtr_oggbase_c::create_standard_file(xtr_base_c *master, KaxTrackEntry &track, LacingType lacing) { KaxCodecPrivate *priv = FindChild<KaxCodecPrivate>(&track); if (!priv) mxerror(boost::format(Y("Track %1% with the CodecID '%2%' is missing the \"codec private\" element and cannot be extracted.\n")) % m_tid % m_codec_id); init_content_decoder(track); memory_cptr mpriv = decode_codec_private(priv); std::vector<memory_cptr> header_packets; try { if (lacing == LACING_NONE) header_packets.push_back(mpriv); else { header_packets = unlace_memory_xiph(mpriv); if (header_packets.empty()) throw false; } header_packets_unlaced(header_packets); } catch (...) { mxerror(boost::format(Y("Track %1% with the CodecID '%2%' does not contain valid headers.\n")) % m_tid % m_codec_id); } xtr_oggbase_c::create_file(master, track); ogg_packet op; for (m_packetno = 0; header_packets.size() > m_packetno; ++m_packetno) { // Handle all the header packets: ID header, comments, etc op.b_o_s = (0 == m_packetno ? 1 : 0); op.e_o_s = 0; op.packetno = m_packetno; op.packet = header_packets[m_packetno]->get_buffer(); op.bytes = header_packets[m_packetno]->get_size(); op.granulepos = 0; ogg_stream_packetin(&m_os, &op); if (0 == m_packetno) /* ID header must be alone on a separate page */ flush_pages(); } /* flush at last header, data must start on a new page */ flush_pages(); }
void xtr_alac_c::create_file(xtr_base_c *master, KaxTrackEntry &track) { init_content_decoder(track); auto channels = kt_get_a_channels(track); auto priv = FindChild<KaxCodecPrivate>(&track); if (!priv) mxerror(boost::format(Y("Track %1% with the CodecID '%2%' is missing the \"codec private\" element and cannot be extracted.\n")) % m_tid % m_codec_id); m_priv = decode_codec_private(priv); if (m_priv->get_size() != sizeof(alac::codec_config_t)) mxerror(boost::format(Y("ALAC private data size mismatch\n"))); xtr_base_c::create_file(master, track); m_out->write(std::string{"caff"}); // mFileType m_out->write_uint16_be(1); // mFileVersion m_out->write_uint16_be(0); // mFileFlags m_out->write(std::string{"desc"}); // Audio Description chunk m_out->write_uint64_be(32ULL); // mChunkSize m_out->write_double(static_cast<int>(kt_get_a_sfreq(track))); // mSampleRate m_out->write(std::string{"alac"}); // mFormatID m_out->write_uint32_be(0); // mFormatFlags m_out->write_uint32_be(0); // mBytesPerPacket m_out->write_uint32_be(caf::defs::default_frames_per_packet); // mFramesPerPacket m_out->write_uint32_be(channels); // mChannelsPerFrame m_out->write_uint32_be(0); // mBitsPerChannel auto kuki_size = 12 + 36 + 8 + (2 < channels ? 24 : 0); // add the size of ALACChannelLayoutInfo for more than 2 channels m_out->write(std::string{"kuki"}); m_out->write_uint64_be(kuki_size); m_out->write_uint8('\0'); m_out->write_uint8('\0'); m_out->write_uint8('\0'); m_out->write_uint8('\14'); m_out->write(std::string{"frma"}); m_out->write(std::string{"alac"}); m_out->write_uint32_be(12 + sizeof(alac::codec_config_t)); // ALAC Specific Info size = 36 (12 + sizeof(ALAXSpecificConfig)) m_out->write(std::string{"alac"}); // ALAC Specific Info ID m_out->write_uint32_be(0L); // Version Flags m_out->write(m_priv); // audio specific config auto alo = caf::channel_layout_t(); if (2 < channels) { switch (channels) { case 3: alo.channel_layout_tag = caf::channel_layout_t::mpeg_3_0_b; alo.channel_bitmap = caf::channel_layout_t::left | caf::channel_layout_t::right | caf::channel_layout_t::center; break; case 4: alo.channel_layout_tag = caf::channel_layout_t::mpeg_4_0_b; alo.channel_bitmap = caf::channel_layout_t::left | caf::channel_layout_t::right | caf::channel_layout_t::center | caf::channel_layout_t::center_surround; break; case 5: alo.channel_layout_tag = caf::channel_layout_t::mpeg_5_0_d; alo.channel_bitmap = caf::channel_layout_t::left | caf::channel_layout_t::right | caf::channel_layout_t::center | caf::channel_layout_t::left_surround | caf::channel_layout_t::right_surround; break; case 6: alo.channel_layout_tag = caf::channel_layout_t::mpeg_5_1_d; alo.channel_bitmap = caf::channel_layout_t::left | caf::channel_layout_t::right | caf::channel_layout_t::center | caf::channel_layout_t::left_surround | caf::channel_layout_t::right_surround | caf::channel_layout_t::lfe_screen; break; case 7: alo.channel_layout_tag = caf::channel_layout_t::aac_6_1; alo.channel_bitmap = caf::channel_layout_t::left | caf::channel_layout_t::right | caf::channel_layout_t::center | caf::channel_layout_t::left_surround | caf::channel_layout_t::right_surround | caf::channel_layout_t::center_surround | caf::channel_layout_t::lfe_screen; break; case 8: alo.channel_layout_tag = caf::channel_layout_t::mpeg_7_1_b; alo.channel_bitmap = caf::channel_layout_t::left | caf::channel_layout_t::right | caf::channel_layout_t::center | caf::channel_layout_t::left_center | caf::channel_layout_t::right_center | caf::channel_layout_t::left_surround | caf::channel_layout_t::right_surround | caf::channel_layout_t::lfe_screen; break; } auto acli = caf::channel_layout_info_t(); put_uint32_be(&acli.channel_layout_info_size, 24); // = sizeof(ALACChannelLayoutInfo) put_uint32_be(&acli.channel_layout_info_id, FOURCC('c', 'h', 'a', 'n')); // = 'chan' put_uint32_be(&acli.channel_layout_tag, alo.channel_layout_tag); m_out->write(&acli, sizeof(acli)); } // Terminator atom m_out->write_uint32_be(8); // Channel Layout Info Size m_out->write_uint32_be(0); // Channel Layout Info ID if (2 < channels) { m_out->write(std::string{"chan"}); // 'chan' chunk immediately following the kuki m_out->write_uint64_be(12ULL); // = sizeof(ALACAudioChannelLayout) m_out->write_uint32_be(alo.channel_layout_tag); m_out->write_uint32_be(alo.channel_bitmap); m_out->write_uint32_be(alo.number_channel_descriptions); } m_free_chunk_offset = m_out->getFilePointer(); // remember the location of m_free_chunk_size = 16384; auto free_chunk = memory_c::alloc(m_free_chunk_size); memset(free_chunk->get_buffer(), 0, sizeof(m_free_chunk_size)); // the 'free' chunk m_out->write(std::string{"free"}); m_out->write_uint64_be(m_free_chunk_size); m_out->write(free_chunk); m_data_chunk_offset = m_out->getFilePointer(); m_out->write(std::string{"data"}); // Audio Data Chunk m_out->write_uint64_be(-1LL); // mChunkSize (= -1 if unknown) m_out->write_uint32_be(1); // mEditCount }
void xtr_ssa_c::create_file(xtr_base_c *master, KaxTrackEntry &track) { KaxCodecPrivate *priv = FindChild<KaxCodecPrivate>(&track); if (!priv) mxerror(boost::format(Y("Track %1% with the CodecID '%2%' is missing the \"codec private\" element and cannot be extracted.\n")) % m_tid % m_codec_id); xtr_base_c::create_file(master, track); m_out->write_bom(m_sub_charset); memory_cptr mpriv = decode_codec_private(priv); const unsigned char *pd = mpriv->get_buffer(); int priv_size = mpriv->get_size(); unsigned int bom_len = 0; byte_order_e byte_order = BO_NONE; // Skip any BOM that might be present. mm_text_io_c::detect_byte_order_marker(pd, priv_size, byte_order, bom_len); pd += bom_len; priv_size -= bom_len; char *s = new char[priv_size + 1]; memcpy(s, pd, priv_size); s[priv_size] = 0; std::string sconv = s; delete []s; const char *p1; if (!(p1 = strstr(sconv.c_str(), "[Events]")) || !strstr(p1, "Format:")) { if (m_codec_id == MKV_S_TEXTSSA) sconv += "\n[Events]\nFormat: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n"; else sconv += "\n[Events]\nFormat: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text\n"; } else if (sconv.empty() || (sconv[sconv.length() - 1] != '\n')) sconv += "\n"; // Keep the Format: line so that the extracted file has the // correct field order. int pos1 = sconv.find("Format:", sconv.find("[Events]")); if (0 > pos1) mxerror(boost::format(Y("Internal bug: tracks.cpp SSA #1. %1%")) % BUGMSG); int pos2 = sconv.find("\n", pos1); if (0 > pos2) pos2 = sconv.length(); std::string format_line = balg::to_lower_copy(sconv.substr(pos1 + 7, pos2 - pos1 - 7)); if (std::string::npos == format_line.find("text")) { if (format_line[format_line.length() - 1] == '\r') { format_line.erase(format_line.length() - 1); --pos2; } format_line += ",text"; sconv.insert(pos2, ", Text"); } m_ssa_format = split(format_line, ","); strip(m_ssa_format, true); sconv = m_conv->native(sconv); m_out->puts(sconv); }
void xtr_usf_c::create_file(xtr_base_c *master, KaxTrackEntry &track) { KaxCodecPrivate *priv = FindChild<KaxCodecPrivate>(&track); if (!priv) mxerror(boost::format(Y("Track %1% with the CodecID '%2%' is missing the \"codec private\" element and cannot be extracted.\n")) % m_tid % m_codec_id); init_content_decoder(track); memory_cptr new_priv = decode_codec_private(priv); m_codec_private.append((const char *)new_priv->get_buffer(), new_priv->get_size()); KaxTrackLanguage *language = FindChild<KaxTrackLanguage>(&track); if (!language) m_language = "eng"; else m_language = std::string(*language); if (master) { xtr_usf_c *usf_master = dynamic_cast<xtr_usf_c *>(master); if (!usf_master) mxerror(boost::format(Y("Cannot write track %1% with the CodecID '%2%' to the file '%3%' because " "track %4% with the CodecID '%5%' is already being written to the same file.\n")) % m_tid % m_codec_id % m_file_name % master->m_tid % master->m_codec_id); if (m_codec_private != usf_master->m_codec_private) mxerror(boost::format(Y("Cannot write track %1% with the CodecID '%2%' to the file '%3%' because track %4% with the CodecID '%5%' is already " "being written to the same file, and their CodecPrivate data (the USF styles etc) do not match.\n")) % m_tid % m_codec_id % m_file_name % master->m_tid % master->m_codec_id); m_doc = usf_master->m_doc; m_master = usf_master; } else { try { m_out = mm_file_io_c::open(m_file_name, MODE_CREATE); m_doc = std::make_shared<pugi::xml_document>(); std::stringstream codec_private{m_codec_private}; auto result = m_doc->load(codec_private, pugi::parse_default | pugi::parse_declaration | pugi::parse_doctype | pugi::parse_pi | pugi::parse_comments); if (!result) throw mtx::xml::xml_parser_x{result}; pugi::xml_node doctype_node, declaration_node, stylesheet_node; for (auto child : *m_doc) if (child.type() == pugi::node_declaration) declaration_node = child; else if (child.type() == pugi::node_doctype) doctype_node = child; else if ((child.type() == pugi::node_pi) && (std::string{child.name()} == "xml-stylesheet")) stylesheet_node = child; if (!declaration_node) declaration_node = m_doc->prepend_child(pugi::node_declaration); if (!doctype_node) doctype_node = m_doc->insert_child_after(pugi::node_doctype, declaration_node); if (!stylesheet_node) stylesheet_node = m_doc->insert_child_after(pugi::node_pi, declaration_node); if (!balg::starts_with(m_simplified_sub_charset, "utf")) declaration_node.append_attribute("encoding").set_value(m_sub_charset.c_str()); doctype_node.set_value("USFSubtitles SYSTEM \"USFV100.dtd\""); stylesheet_node.set_name("xml-stylesheet"); stylesheet_node.append_attribute("type").set_value("text/xsl"); stylesheet_node.append_attribute("href").set_value("USFV100.xsl"); } catch (mtx::mm_io::exception &ex) { mxerror(boost::format(Y("Failed to create the file '%1%': %2%\n")) % m_file_name % ex); } catch (mtx::xml::exception &ex) { mxerror(boost::format(Y("Failed to parse the USF codec private data for track %1%: %2%\n")) % m_tid % ex.what()); } } }