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_wav_c::create_file(xtr_base_c *master, KaxTrackEntry &track) { init_content_decoder(track); int channels = kt_get_a_channels(track); int sfreq = (int)kt_get_a_sfreq(track); int bps = kt_get_a_bps(track); if (-1 == bps) mxerror(boost::format(Y("Track %1% with the CodecID '%2%' is missing the \"bits per second (bps)\" element and cannot be extracted.\n")) % m_tid % m_codec_id); xtr_base_c::create_file(master, track); memcpy(&m_wh.riff.id, "RIFF", 4); memcpy(&m_wh.riff.wave_id, "WAVE", 4); memcpy(&m_wh.format.id, "fmt ", 4); memcpy(&m_wh.data.id, "data", 4); put_uint32_le(&m_wh.format.len, 16); put_uint16_le(&m_wh.common.wFormatTag, 1); put_uint16_le(&m_wh.common.wChannels, channels); put_uint32_le(&m_wh.common.dwSamplesPerSec, sfreq); put_uint32_le(&m_wh.common.dwAvgBytesPerSec, channels * sfreq * bps / 8); put_uint16_le(&m_wh.common.wBlockAlign, 4); put_uint16_le(&m_wh.common.wBitsPerSample, bps); m_out->write(&m_wh, sizeof(wave_header)); }
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_wav_c::create_file(xtr_base_c *master, KaxTrackEntry &track) { init_content_decoder(track); auto channels = kt_get_a_channels(track); auto sfreq = static_cast<int>(kt_get_a_sfreq(track)); auto bps = kt_get_a_bps(track); auto block_align = bps * channels / boost::math::gcd(8, bps); if (-1 == bps) mxerror(boost::format(Y("Track %1% with the CodecID '%2%' is missing the \"bits per second (bps)\" element and cannot be extracted.\n")) % m_tid % m_codec_id); xtr_base_c::create_file(master, track); memcpy(&m_wh.riff.id, "RIFF", 4); memcpy(&m_wh.riff.wave_id, "WAVE", 4); memcpy(&m_wh.format.id, "fmt ", 4); memcpy(&m_wh.data.id, "data", 4); put_uint32_le(&m_wh.format.len, 16); put_uint16_le(&m_wh.common.wFormatTag, 1); put_uint16_le(&m_wh.common.wChannels, channels); put_uint32_le(&m_wh.common.dwSamplesPerSec, sfreq); put_uint32_le(&m_wh.common.dwAvgBytesPerSec, channels * sfreq * bps / 8); put_uint16_le(&m_wh.common.wBlockAlign, block_align); put_uint16_le(&m_wh.common.wBitsPerSample, bps); m_out->write(&m_wh, sizeof(wave_header)); if (m_codec_id == MKV_A_PCM_BE) m_byte_swapper = [bps](unsigned char const *src, unsigned char *dst, std::size_t num_bytes) { mtx::bytes::swap_buffer(src, dst, num_bytes, bps / 8); }; }
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_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()); } } }